第四章 服務器進程和ASP Server對象
前面的章節已經研究了ASP的一些內置對象。重點介紹的對象有Request、Response、session和application對象。ASP中另一個比較主要的對象為Server對象。本章重點介紹這個對象的背景知識和使用方法。
Server對象在服務器端腳本中通過實例和使用其他外部對象和組件,提供了一種擴展ASP頁的功能的方法。事實上,許多人認為這個對象是ASP之所以能夠流行的主要因素。引入Server對象的意義很大,這意味著ASP不必提供人們所需要的所有屬性。它可調用其他應用程序和組件完成指定工作。
這也恰好符合了構建由獨立的對象組成的應用程序的總體目標,而不是構建通常見到的那種耗盡硬盤空間的“可做每件事情”的巨型程序。不僅僅是在計算機的世界中,整個世界正在朝著組件和“即插即用”概念方面發展。如今,當汽車或電視機發生故障時,技師或工程師很可能會拔出有問題的部件並且插入一個新的部件,因此,汽車維護人員或電視機維修人員的工作也變成了面向對象的。
然而,IIS同樣支持使用外部對象和與服務器環境進行交互作用的許多傳統方法。這是一個特定的例外,這些方法並不是真正的ASP組成部分,但通常的確非常有用,並且通過Server對象的一些新特性已經與ASP很好地進行了集成。本章將簡要地回顧這些傳統方法,然後詳細地介紹ASP Server對象。
本章的主要內容為:
· 傳統的服務器端包含(SSI)指令的背景知識和使用方法。
· Server對象所要完成的任務,以及與SSI的比較。
· 如何使用Server對象實例、外部組件和應用程序。
· 如何使用Server對象執行封裝的腳本或其他ASP頁面。
· 如何使用Server對象管理在腳本中出現的錯誤。
· 如何使用Server對象完成與Html或HTTP兼容的格式轉換。
Server對象是ASP頁中的錯誤處理過程的一部分,在IIS 5.0和ASP 3.0中是新的內容。本章介紹該對象是如何工作的。因為有單獨的一章(第7章)專門討論有關調試和錯誤處理方面的所有問題。所以本章只簡要地討論錯誤處理方法,並且僅限於Server對象直接涉及的過程。
4.1 動態頁中服務器端的處理
就服務器端處理而言,ASP是產生動態Web網頁的一種相對較新的技術。動態頁意味著什麼呢?先暫時不考慮客戶端相關功能上的進展,也不討論客戶端腳本、Java Applet、動態Html或ActiveX控件等內容。這裡的動態頁是專指服務器響應客戶端請求產生的頁面,並且根據情況每次產生的頁面可能是不同的。
舉個簡單的例子,創建一個只包含當前日期和時間的頁面。每次請求該頁面時將顯示一個不同的值,因為日期和時間取決於服務器的時鐘,或取決於提供日期和時間的一個資源(例如一個獨立的服務器或來自於互聯網上一個標准時鐘)。當然,實際上動態頁要比這復雜得多,也許顯示數據庫記錄的當前值或者郵件服務器上等待著的郵件消息的摘要。重要的是服務器不僅閱讀一個無格式的Html頁面、或磁盤上的文本文件以及把它們發送給客戶,而且,必須完成一些工作來創建該頁面。
Internet服務器應用編程接口
第1章介紹了創建動態頁的一些方法。傳統的技術是使用與Web服務器的一個接口,它被稱為Internet服務器應用編程接口(Internet Server Application PRogramming Interface,ISAPI)。
ISAPI可用於執行其他的應用程序,這些應用程序通過C語言風格的stdin和stdout數據流函數來讀取客戶端請求的值並創建Web服務器的響應。ISAPI應用程序所必須做的全部事情就是編寫相應結果頁面的文本和Html,並通過stdout函數輸出到Web服務器。事實上ASP DLL內部真正做的事情是更面向對象的。
IIS自開始就運行ISAPI的應用程序和腳本解釋器。它提供一個特殊的解釋器動態鏈接庫,給出訪問服務器的請求和響應的另一種方法,盡管受到一定的限制。它通過服務器端包含指令實現,之所以這樣說,是因為它們是在服務器上執行的,並且結果包含在傳送給客戶端的響應中。這個特性在IIS中是通過一個名為ssinc.dll的動態鏈接庫實現的。缺省情況下,IIS把文件擴展名為.sHtml、.shtm或.stm的任意頁面都映射到這個動態鏈接庫。打開默認Web站點的PropertIEs對話框,在Application Setting中單擊Configuration按鈕,可以看到這種映射,如圖4-1所示:
圖4-1 Application Configuration對話框
這樣,帶有這些被映射的文件擴展名的頁面將被傳送給ssinc.dll進行處理。因此,執行頁面中所有的服務器端包含語句,結果(如有的話)插入到服務器的響應中,即插入到客戶端接收到的頁面中。
因為這些文件是映射到ssinc.dll文件而不是映射到ASP動態鏈接庫(asp.dll)的,所以在這些頁面中的所有ASP代碼將被忽略並且按照原有狀態傳送給客戶端,客戶端將能夠看到這些腳本。然而,在ASP 3.0版本中有一個避免這種情況的方法,稍後在討論Server對象的Execute和Transfer方法時,研究這個方法。
4.2 服務器端的包含指令
利用服務器端的包含(SSI)語句(或者指令)能夠做些什麼呢?實際上不多,除非打算創建在Web服務器上運行的可執行文件,並通過stdin和stdout函數訪問ISAPI。這就意味能夠用C、C++或其他語言(如Delphi)等編寫它們,但VB並不適合。此外,使用SSI指令能夠做的事情可達到與在ASP中實現同樣好的效果。許多方法中,IIS的SSI特性對使用這些特性的原有的Web網站和Web頁面具有向下兼容性。
然而,可能有時會希望在站點上使用SSI而不是ASP。在IIS 5.0中,服務器端的包含指令能夠比以前更加容易地集成到一個遠程站點上的ASP頁,它們是有用的,特別是作為執行操作系統命令或原有的CGI應用程序的一種方式。後面將會非常詳細地介紹可用的指令。
#include指令是這些指令之一,它已經與ASP一起使用了一段時間了,同樣也在SSI頁中使用。事實上,這已經對那些不具備傳統的web開發背景的ASP開發人員帶來了很多混亂。
4.2.1 不可思議的ASP #include指令
在一個ASP頁中,可以使用#include指令把另一個文件的內容插入到當前的頁面中:
<!-- #include file=”/scripts/usefulbits.inc” -->
這條指令讀取該文件的全部內容並插入到該頁中,替代<!-- #include.. -->行。這是一種非常有用的插入Html段落的技術,可反復使用。也常用該指令來插入代碼段。例如,如果有一個包含幾個腳本函數(或者只是單行腳本代碼)的文件同時在幾個頁面中使用,則可以使用#include指令將其插入到需要它的每個頁中。
通過把腳本和內容分開的方法,給頁面提供了一個組成層次。這意味著如果對腳本進行了修改,在客戶端再次打開該頁面時,腳本的修改情況自動地反映到使用包含文件的每個頁面中。包含文件也是一種插入服務器特定的信息的簡單方法,所以把站點轉移到另一個服務器不意味著必須編輯涉及原來服務器的所有頁面(明顯的例子是數據庫連接字符串或指定一個完整的URL或服務器名字的鏈接)。這可以極大地減少維護費用。
例如,可以把下面的內容作為一個包含文件,命名為connect.inc:
<%
strConnect = “SERVER=myserver;DATABASE=mydb;DRIVER={SQL Server};” _
& “UID=username;PWD=secretpassWord”
%>
然後可以在任何頁中使用這個文件:
<!-- #include file=”path_to_file\connect.inc” -->
<%
…
strTheConnectionString = strConnect ‘From include file
…
%>
使用包含文件的另一種情況是有些內容需要按指定的時間間隔進行修改。例如,在Wrox Web Deverloper站點上顯示書目列表的網頁,它包含了一個表,其中提供了所有的封面、書名和一些按鈕,如圖4-2所示:
圖4-2 顯示書目列表的網頁
這個表的Html和文本保留在一個單獨的文件中,該文件通過一條單獨的#include語句包含在主頁中。每次一本新書加入到該網頁所基於的數據庫中時,那個包含文本文件根據該數據庫的情況重新創建,並作為一個文本文件寫到磁盤上。
這個技術大大減少了在Web服務器和數據庫服務器上的工作量,對該站點的訪問者實現較快地響應。
1. 包含文件和ASP
在ASP網頁(即帶有.asp文件擴展名的網頁)中使用的#include指令不能像一條真正的SSI指令那樣進行處理,它僅是一條ASP能夠識別並進行語法分析的特別指令。ssinc.dll直接用於執行SSI #include指令。然而這個由相應文件的內容替代#include指令的頁面由ASP解釋。
這意味著ASP對#include指令所進行的操作不實施控制。例如,可以試驗以下代碼:
<%
‘This will *not* work
strIncludeURL = Request.Form(“FileName”)
%>
…
<!-- #include file=”<% = strIncludeURL %>” -->
ssinc.dll將查找名為<% = strIncludeURL %>的文件,並且不可能找到,因此這段代碼不會工作。
2. 包含文件的安全性
如果沒有包含可執行腳本,在Web服務器上的ASP網頁不能通過IIS的Web服務程序下載到一個客戶端。但是,有人已經發現了偶然的安全性漏洞,比如著名的$DATA問題,所有在NTFS格式化的磁盤上保留Web內容的Web服務器都存在相應的問題。在IIS 5.0中這個問題已經得到解決。
$DATA問題的出現是因為在Windows NTFS驅動器上的所有文件都有一個缺省的“值”,即是該文件的內容,並且通過文件名加後綴“::$DATA”來指示。將其增加到一個ASP網頁的URL的末尾將打亂IIS中的腳本映射關系,且允許服務器不對其中包含的腳本進行處理而不載該頁面。對IIS 4.0和早期版本,有一個方法可以解決這個問題,或者可以只是增加幾個映射來強制IIS正常地執行該網頁:即增加對“.asp::$DATA”和“.asa::$DATA”的映射,兩者都指向ASP.dll文件。
包含文件的擴展各一般是.inc或.txt。如果在站點上發現一個包含文件的路徑和文件名,可通過把包含文件的URL鍵入到浏覽器的地址欄中,下載該包含文件,而不會把其作為ASP網頁的一部分來執行。為防止出現這樣情況,特別是在文件包含有敏感信息(諸如一個數據庫鏈接字符串)的情況下,可能希望包含文件的擴展名為.asp。在這種情況下,如果試圖下載一個包含文件,它將首先被傳送到ASP,ASP將執行該文件中的所有腳本代碼,並只發送出結果。如在包含文件中定義的一個鏈接字符串如下:
<%
strConnect = “SERVER=myserver;DATABASE=mydb;DRIVER={SQL Server};” _
& “UID=username;PWD=secretpassWord”
Response.Write vbCrlf ‘Output a carriage return character
%>
客戶端只能接受到單個回車符而不是腳本代碼,因為該文件已經被ASP在服務器上執行了。如果不包含回車符,浏覽器將掛起並等待一個響應(這並不是我們的問題,因為我們確實不打算允許用戶直接訪問這個文件)。
IIS 5.0和Windows的訪問控制列表
在IIS 5.0中,Microsoft已經改變了Web服務器和操作系統訪問服務器端包含文件的方法。
在IIS早期版本中,當ssinc.dll載入一個虛擬URL(即使用VIRTUAL = “filename”而不是FILE = “filename”)定位的一個包含文件時,將繞過Windows本身的安全性檢查並忽略該文件及所存儲的目錄上的任何安全性設置。現在,在IIS 5.0中,運行當前ASP或SSI頁面的帳號必須與對該文件和目錄在Windows訪問控制列表(ACL)中設置的權限相一致。如果不一致,該SSI指令運行將失敗。
4.2.2 服務器端包含指令概要
除了已經討論過的#include語句以外,還有IIS支持的五條服務器端包含指令(記住,除#include以外,這些語句不能在ASP網頁中執行)。這些服務器端包含指令及說明如表4-1所示:
表4-1 服務器端包含指令及說明
指 令
說 明
#include
把一個指定文件的內容插入到將被發送給客戶端的響應流中並代替該指令。例如:
<!-- #include FILE = “usefulbits.inc” -->
這條指令把名為usefulbits.inc文件的內容插入到響應中。這個文件可以由一個相對或全路徑與文件名的組合描述,如FILE=”..\scripts\myscr.inc”。通過使用VIRTUAL屬性,可使用一個虛擬的相對或絕對路徑來描述它,例如:
<!-- #include VIRTUAL=”/mysite/ussefulbits.inc” -->
<!-- #include VIRTUAL=”../../thisbit/usefulbits.inc” -->
#config
說明在其後的指令中將用於數據、時間和文件大小以及返回給客戶端的一般性的SSI錯誤信息的文本的格式。例如:
<!-- #config ERRMSG=”SSI Processing Error” -->
設置SSI錯誤信息內容為’SSI Processing Error’。
<!-- #config TIMEFMT=”%A,%B %d %Y %H:%M:%S” -->
設置由其後的SSI指令返回的日期和時間的格式。這個例子設置一個格式風格:Saturday, August 14 1999 10:34:50。可以用於格式字符串的標志的列表在附錄C中給出。
<!-- #config SIZEFMT=”BYTES” -->
設置由其後的IIS指令返回的文件大小的單位。這個例子設置單位為字節。對SIZEFMT可供選擇的值是“ABBREV”,指明計算值將千字節(KB)返回文件的大小
#echo
把一個HTTP環境變量的值插入到發送給客戶端的響應流中並替換該指令。例如:
<!-- #echo VAR=”SERVER_NAME” -->
寫出正在執行指令到該網頁的服務器的名字
#exec
執行一個程序或一個服務器外殼命令,例如:
<!-- #exec CGI=”/scripts/myapp.exe?value1=this&value2=that -->
執行名為myapp.exe的CGI程序,允許傳遞查詢字符串,程序在單獨內存中執行。
<!-- #exec CMD=”cmd.exe/c IISreset/stop” -->
啟動特定操作系統命令解釋器(cmd.exe)並執行命令IISreset/stop。/c表示當命令結束時,命令解釋器也結束。使用CMD要添加下列注冊表項:
HKEY_LOCAL_MacHINE/SYSTEM/CurrentControlSet/Services/w3SVC
/Parameters/SSIEnableCmdDirective
設置值為1,並重啟動WWW服務,就允許CMD標志用於#exec指令中。值為0,則禁止使用,並防止未驗證的使用
#flastmod
把一個指定的文件上一次修改的日期和時間插入到發送給客戶端的響應流中並代替該指令。
例如:
<!-- #flastmod FILE=”Default.ASP” -->
像#include指令一樣,也可以使用虛擬路徑對該文件進行定義,如:
VIRTUAL=”/mysite/usefulbits.inc”
或
VIRTUAL=”../thisbit/usefulbits.inc”
#fsize
把一個指定的文件的大小插入到發送給客戶端的響應流中並代替該指令。例如:
<!-- #fsize FILE=”Default.ASP” -->
象#include指令一樣,也可以使用虛擬路徑對該文件進行定義,如:
VIRTUAL=”/mysite/usefulbits.inc”
或
VIRTUAL=”../thisbit/usefulbits.inc”
1. IISRESET實用程序
iisreset.exe是由IIS 5.0提供的一個新的實用程序。作為一個命令行的實用程序,如果用於執行該實用程序的帳號具有管理員權限,它對於控制運行在本地或一個網絡計算機上的Internet聯網服務器是非常有用的。它可用於以正確的順序停止或啟動所有的服務、顯示服務的狀態、重新引導服務器以及允許或禁止服務的管理。例如:
IISreset /RESTART /TIMEOUT:30 /REBOOTONERROR
這將以正確的順序停止和重新啟動所有Internet服務。如果一種服務在指定的超時周期(30秒)內未能停止或重新啟動,服務器將重新引導。可以用在CMD類型的#echo SSI指令中的一些開關,使該頁面不能進行匿名訪問並且要求用戶提供在目標服務器上具有管理員權限的有效帳號的詳細情況。這個實用程序的完整描述和可用的命令開關在附錄C中。
2. NET STOP和NET START命令
如果用來執行實用程序net.exe的帳號具有管理員權限,它可以用來管理服務器上運行的任何服務(即可以是本地的也可以是來自其他的一個計算機)。雖然不提倡把該程序用於Internet服務(如WWW或FTP服務),但其停止和啟動其他服務的功能是非常有用的。事實上,net命令同樣可以用於一系列的其他網絡相關命令。
語法是:
net [start | stop] service_name
例如,可以用命令net stop cisvc和net start cisvc來停止和啟動Miscrosoft Indexing Service。可以用CMD類型的#echo SSI指令使該頁面不能進行匿名訪問並要求用戶提供在目標服務器上的具有管理員權限的有效帳號的詳細情況。稍後將看到一個這樣的例子。
在Windows 2000幫助文件中可以找到net命令的所有選項和開關的一個完整列表。從Start菜單中選擇Help項,在Help窗口的Index頁查找“netcommands”。