2011-02-28 12:20 .net httpHandler和httpModule

摘自:http://hi.baidu.com/guoxiaoming/item/a28d53147b44db3eb93180ca

 

net httpHandler和httpModule

HttpModule是向實現類提供模塊初始化和處置事件。當一個HTTP請求到達HttpModule時,整個ASP.NET
Framework系統還並沒有對這個HTTP請求做任何處理,也就是說此時對於HTTP請求來講,HttpModule是一個HTTP請求的“必經之路”,所以可以在這個HTTP請求傳遞到真正的請求處理中心(HttpHandler)之前附加一些需要的信息在這個HTTP請求信息之上,或者針對截獲的這個HTTP請求信息作一些額外的工作,或者在某些情況下乾脆終止滿足一些條件的HTTP請求,從而可以起到一個Filter過濾器的作用。

1、asp.net的HTTP請求處理過程



說明:

(1)、客戶端瀏覽器向服務器發出一個http請求,此請求會被inetinfo.exe進程截獲,然後轉交給aspnet_isapi.dll進程,接着它又通過Http
Pipeline的管道,傳送給aspnet_wp.exe這個進程,接下來就到了.net
framework的HttpRunTime處理中心,處理完畢後就發送給用戶瀏覽器。

(2)、當一個http請求被送入到HttpRuntime之後,這個Http請求會繼續被送入到一個被稱之爲HttpApplication
Factory的一個容器當中,而這個容器會給出一個HttpApplication實例來處理傳遞進來的http請求,而後這個Http請求會依次進入到如下幾個容器中:HttpModule
--> HttpHandler Factory -->
HttpHandler。當系統內部的HttpHandler的ProcessRequest方法處理完畢之後,整個Http
Request就被處理完成了,客戶端也就得到相應的東東了。
(3)完整的http請求在asp.net
framework中的處理流程:

HttpRequest-->inetinfo.exe->ASPNET_ISAPI.DLL-->Http
Pipeline-->ASPNET_WP.EXE-->HttpRuntime-->HttpApplication
Factory-->HttpApplication-->HttpModule-->HttpHandler
Factory-->HttpHandler-->HttpHandler.ProcessRequest()


也就是說一個HTTP請求在HttpModule容器的傳遞過程中,會在某一時刻(ResolveRequestCache事件)將這個HTTP請求傳遞給HttpHandler容器。在這個事件之後,HttpModule容器會建立一個HttpHandler的入口實例,但是此時並沒有將HTTP請求控制權交出,而是繼續觸發AcquireRequestState事件以及PreRequestHandlerExcute事件。在PreRequestHandlerExcute事件之後,HttpModule窗口就會將控制權暫時交給HttpHandler容器,以便進行真正的HTTP請求處理工作。


而在HttpHandler容器內部會執行ProcessRequest方法來處理HTTP請求。在容器HttpHandler處理完畢整個HTTP請求之後,會將控制權交還給HttpModule,HttpModule則會繼續對處理完畢的HTTP請求信息流進行層層的轉交動作,直到返回到客戶端爲止。

PS:紅色的HttpApplication實例在HttpModule的Init方法中會用到。



(4)如果想在中途截獲一個httpRequest並做些自己的處理,就應該在HttpRuntime運行時內部來做到這一點,確切的說是在HttpModule這個容器中來實現。


2、HttpModule工作原理


    
負責監聽HttpRequest,同時對HttpRequest增添或者過濾掉一部分內容。也就是說,當一個HTTP請求到達HttpModule時,整個ASP.NET
Framework系統還並沒有對這個HTTP請求做任何處理,也就是說此時對於HTTP請求來講,HttpModule是一個HTTP請求的“必經之路”,所以可以在這個HTTP請求傳遞到真正的請求處理中心(HttpHandler)之前附加一些需要的信息在這個HTTP請求信息之上,或者針對截獲的這個HTTP請求信息作一些額外的工作,或者在某些情況下乾脆終止滿足一些條件的HTTP請求,從而可以起到一個Filter過濾器的作用。

HttpModule實現了接口IHttpModule,我們可以自定義實現該接口的類,從而取代HttpModule。

asp.net默認的HttpModule如下:

System.Web.SessionState.SessionStateModule;
System.Web.Security.WindowsAuthenticationModule;
System.Web.Security.FormsAuthenticationModule;
System.Web.Security.PassportAuthenticationModule;
System.Web.Security.UrlAuthorizationModule;
System.Web.Security.FileAuthorizationModule;

3、編寫自己的HttpModule

要實現HttpModule,必須實現接口IHttpModule。下面是IHttpModule接口分析:

using System;
namespace System.Web{ publicinterface IHttpModule { // 銷燬不再被HttpModule使用的資源void
Dispose(); // 初始化一個Module,爲捕獲HttpRequest做準備void Init(HttpApplication
context); }}


下面是自己的HttpModule:

using System; using System.Web; namespace ClassLibrary1{
publicclass MyHttpModule : IHttpModule { public void Dispose() { } publicvoid
Init(HttpApplication context) { context.BeginRequest += new
EventHandler(Application_BeginRequest); context.EndRequest += new
EventHandler(Application_EndRequest); } publicvoid
Application_BeginRequest(object sender, EventArgs e) { HttpApplication
application = sender as HttpApplication; HttpContext context =
application.Context; HttpResponse response =
context.Response; response.Write("這是來自自定義HttpModule中有BeginRequest"); } public
void Application_EndRequest(object sender, EventArgs e) { HttpApplication
application = sender as HttpApplication; HttpContext context =
application.Context; HttpResponse response = context.Response;
response.Write("這是來自自定義HttpModule中有EndRequest"); } } }


web.config

<httpModules> <add name="myHttpModule"
type="ClassLibrary1.MyHttpModule,ClassLibrary1"/> </httpModules>


default.aspx.cs

using System; using System.Collections.Generic; using
System.Linq; using System.Web; using System.Web.UI; using
System.Web.UI.WebControls; public partial class _Default : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
Response.Write("<br/><br/>來自Default.aspx頁面<br/>"); }}




4、HttpModule內部事件機制和生命週期


HttpModule對HttpApplication實例進行處理,而HttpApplication有很多事件(對應不同的生命期),這樣就衍生出HttpModule內部事件機制和生命週期。

(1)、HttpModule的事件

  BeginRequest指示請求處理開始AuthenticateRequest封裝請求身份驗證過程AuthorizeRequest封裝檢查是否能利用以前緩存的輸出頁面處理請求的過程ResolveRequestCache從緩存中得到相應時候觸發AcquireRequestState加載初始化Session時候觸發PreRequestHandlerExecute在Http請求進入HttpHandler之前觸發PostRequestHandlerExecute在Http請求進入HttpHandler之後觸發ReleaseRequestState存儲Session狀態時候觸發UpdateRequestCache更新緩存信息時觸發EndRequest在Http請求處理完成的時候觸發PreSendRequestHenaders在向客戶端發送Header之前觸發PreSendRequestConternt在向客戶端發送內容之前觸發


說明:
a、BenginRequest和EndRequest分別是HttpModule容器最開始的和最後的事件;

b、EndRequest之後還會觸發PreSendRequestHeaders事件和PreSendRequestContent事件,這不是在HttpModule外的兩個事件,表示HttpModule結束,即將開始向Client發送數據。


(2)、驗證HttpModule生命週期

與HttpHandler的交互:


說明:

a、HttpModule容器會將HttpRequest傳遞到HttpHandler容器,這個時間點是ResolveRequestCache事件

b、HttpModule容器會建立HttpHandler實例作爲入口——Session從此生效

c、觸發AcquireRequestState事件以及PreRequestHandlerExecute事件

d、HttpModule容器便將對HttpRequest的控制權轉讓給HttpHandler容器

e、HttpHandler容器處理HttpRequest——使用自身的ProcessRequest方法,將對其控制權又還給HttpModule容器——之後Session失效。



<add name="HttpModule1"
type="MyHttpModule.HttpModule1,MyHttpModule"/> <add name="HttpModule2"
type="MyHttpModule.HttpModule2,MyHttpModule"/>


HttpModule1和HttpModule2模仿ValidaterHttpModuleEvents編寫(除了類名改變外,事件和方法不變),不貼代碼了。運行結果如下:



從運行結果可以看到,在web.config文件中引入自定義HttpModule的順序就決定了多個自定義HttpModule在處理一個HTTP請求的接管順序。



(3)、利用HttpModule實現終止此次HttpRequest請求


在BeginRequest事件中,使用HttpApplication.CompleteRequest()方法可以實現當滿足一定條件時終止此次HttpRequest請求

using System; using System.Web; namespace ClassLibrary1{ public class
MyHttpModule : IHttpModule { publicvoid Dispose() { } publicvoid
Init(HttpApplication context) { context.BeginRequest += new
EventHandler(Application_BeginRequest); } public void
Application_BeginRequest(object sender, EventArgs e) { HttpApplication
application = sender as HttpApplication; application.CompleteRequest();
application.Context.Response.Write("請求被終止"); } }}



說明:

a、對於一個HttpModule,在BeginRquest中終止,但是仍然會調用EndRequest事件,以及PreSendRequestHeaders事件和PreSendRequestContent事件。也可以說是直接跳轉到EndRequest事件,而不會調用這期間的事件

b、如果有兩個HttpModule,在第一個HttpModule的BeginRequest中終止,僅僅不會調用第二個HttpModule的BeginRequest,但仍然會調用兩個EndRequest事件,以及PreSendRequestHeaders事件和PreSendRequestContent事件。看下面的圖示:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章