HTTP處理常式是真正負責處理請求的組件,它實現了IHttpHandler介面。該介面的ProcessRequest方法是控制請求處理的“中央控制台”。如,Page類實現IHttpHandler介面,它的ProcessRequest方法負責載入和儲存檢視狀態,還負責引發一些常見的事件(Init、Load、PreRender等)。
ASP.NET會將每個傳入的HTTP請求映射到相應的HTTP處理常式。HTTP處理常式工廠建立這些處理常式的執行個體對象(如,PageHandlerFactory類能解析被請求的aspx資源的原始碼,編譯後返回代表相應頁面的類執行個體)。
HTTP模組是實現IHttpModule介面的類,用於處理運行時事件。模組能處理兩種類型的公用事件,分別是HttpApplication引發的事件(包括非同步事件)和其他HTTP模組引發的事件。如,SessionStateModule是ASP.NET內建的模組之一,用於為應用程式提供工作階段狀態服務。它能引發End和Start事件,而其他模組可通過Session_End和Session_Start這樣的簽名來對其進行處理。
HTTP處理常式和HTTP模組分別對應的於ISAPI擴充和ISAPI篩選器。雖然功能相同,但處理常式和模組的編程模型要簡單得多。
ISAPI代表“Internet伺服器應用程式編程介面”(Internet Server Application Programming Interface),用於IIS與外部組件互動的協議。ISAPI模型基於一種Microsoft Win32非託管動態連結程式庫,暴露兩個函數。該模型在IIS 7.0中獲得了顯著的擴充,基於HTTP處理常式和模組,在很大程度上對應於ASP.NET可擴充模型。
IIS可擴充API概述
從根本上講,WEB伺服器是一種伺服器應用程式,可通過多種Internet協議與之串連(如HTTP、FTP、NNTP、SMTP等)。
Web伺服器一般還提供API(API),用於對伺服器的功能進行改進和定製。曆史上出現的第一種擴充API是通過網關介面(Common Getway Interface,CGI)。CGI應用程式處理每個請求都要建立新的進程,不適於高吞量的Web網站,在現代的應用程式中不再使用它了。IIS支援CGI應用程式,但如果需要向後相容,應避免使用該功能。新版本的Web伺服器提供了一種更高效的替代品模型來擴充這種模組的功能。在IIS中,這種替代模型採用了ISAPI介面的形式。
ISAPI模型
IIS將ISAPI組件(Win32 DLL)載入到自己的進程中,隨後,IIS會調用該DLL上的公用進入點對請求進行處理。ISAPI組件在IIS關閉前會一直被保留,處理請求不會對Web伺服器的活動有進一步的影響。這種模型的弊端在於,由於組件載入到Web伺服器的進程中,它發生的任何錯誤都會對整個伺服器及所有安裝的應用程式產生致使的影響。但從IIS 4.0開始已經採取了一些措施來解決這個問題。在IIS 6.0出現之前,我們可以為新安裝的應用程式設定保護層級,其中含有低、中、高3個選項。
如果選擇低級保護,應用程式(及其擴充)會運行在Web伺服器的進程(inetinfo.exe)中;如果選擇中級保護,所有應用程式會集中在池中,由另一個背景工作處理序(dllhost.exe)的執行個體管理;如果選擇進階保護,每個被設為High的應用程式會由各自的背景工作處理序(dllhost.exe)來管理。
運行在IIS 6.0下的應用程式可以按應用程式集區進行分組,我們能選擇利用現有的池還是建立新的。處於同一個池中的應用程式共用相同的運行時設定和相同的背景工作處理序,即w3wp.exe。
ISAPI模型在編程模型上有一個嚴重缺陷。ISAPI組件必須使用C或C++開發,還應考慮多線程,錯誤和運行時故障會影響整個應用程式,因而編寫這種程式應極為謹慎。
從IIS 6.0開始,構建於IIS之上的所有功能,其編程必須遵循ISAPI模型的規範。ASP和ASP.NET也不例外。如今,整個ASP.NET平台與IIS緊密整合,但二者並不是一體的。核心組件aspnet_isapi.dll是IIS與ASP.NET運行時環境的橋樑。在aspx資源的請求傳入時,IIS會將控制權交給aspnet_isapi.dll,而該組件再將請求交給通用語言執行平台(CLR)執行個體中的ASP.NET管道。
ISAPI組件的結構
ISAPI擴充通過DLL結尾的URL進行調用,如下所示:
http://www.contoso.com/apps/hello.dll
該DLL必須暴露兩個函數:GetExtensionVersion和HttpExtensionProc。GetExtensionVersion函數用於設定ISAPI伺服器擴充的版本和名稱。當該擴充被載入時,GetExtensionVersion函數會最先被調用。但它只調用一次,用於對內部變數進行初始化。如果一切正常,該函數會返回true。如果發生錯誤,該函數會返回false,Web伺服器會終止相應DLL的載入,並向系統日誌發送一條訊息。
HttpExtensionProc函數為ISAPI組件的核心。該函數能夠接收請求的基本HTTP資訊(如,查詢字串和標題),執行期望的操作,並準備將響應發送給瀏覽器。
ISAPI編程模型由兩種組件構成:ISAPI擴充和ISAPI篩選器。
ISAPI擴充
ISAPI擴充是CGI應用程式的IIS進程內版本。IIS擴充的工作方式與ASP或ASP.NET頁面相同,它會擷取與HTTP請求相關的資訊,並產生有效和HTTP響應。
ISAPI擴充由已編譯的代碼構成,如果要對其進行修改,每次都需要重新編譯並重新載入。如果DLL載入到Web伺服器的記憶體中,Web伺服器必須停止運行;如果DLL被載入到單獨進程的上下文中,那麼該進程必須停止運行;若使用外部進行,ISAPI擴充的執行速度不像在進程內那樣快,但不會影響到IIS的穩定性。
ISAPI篩選器
ISAPI篩選器是一種組件,能夠捕獲特定的伺服器事件並對其進行處理。在載入時,篩選器會指示它能夠處理的事件。如果其中的某個事件被引發,篩選器便會處理它們,或將其傳給其他篩選器。
篩選器只能在進程內模式下運行。它可以被整個Web伺服器共用,也可以針對特定的Web網站。
ISAPI篩選器能夠實現自訂身分識別驗證模式、壓縮、加密、日誌記錄及請求分析之類的功能。在處理傳入和傳出資料流方面,ISAPI篩選器有非常大的開發潛力,且非常靈活。
IIS 7.0的革新
1. 統一的運行時環境
IIS 7.0在某種程式上體現了ASP.NET與IIS平台的統一。HTTP處理常式、HTTP模組、運行管道和設定檔成為公用環境的組成元素。IIS內部的整個管道被組件化,能包容多個獨立且可配置的組件。ASP.NET應用程式的web.config檔案中加入了一個新區段,專門用於配置IIS環境。因此,ASP.NET運行庫得到了擴充,能與外圍Web伺服器環境進行互動,還能替換其中的組件。
2. 託管的ISAPI擴充和篩選器
若希望在IIS 7.0之前的版本中控制傳入的請求,除了通過MFC或Active Template Library(ATL)來編寫C或C++ DLL以外,別無他法。HTTP處理常式和模組是ASP.NET特有的功能,但僅能處理ASP.NET特定的資源,且請求經IIS驗證後才會交給ASP.NET。
在IIS 7.0中,我們可以編寫HTTP處理常式和模組來對任何請求進行篩選,通過.NET代碼為Web伺服器能夠處理的所有資源添加新功能。確切地講,我們照舊編寫HTTP處理常式和模組,但可以為任何類型註冊它們。