HttpModule是向實現類提供模塊初始化和處置事件。當一個HTTP請求到達HttpModule時,,整個ASP.NET Framework系統(tǒng)還并沒有對這個HTTP請求做任何處理,,也就是說此時對于HTTP請求來講,HttpModule是一個HTTP請求的“必經之路”,,所以可以在這個HTTP請求傳遞到真正的請求處理中心(HttpHandler)之前附加一些需要的信息在這個HTTP請求信息之上,,或者針對截獲的這個HTTP請求信息作一些額外的工作,或者在某些情況下干脆終止?jié)M足一些條件的HTTP請求,,從而可以起到一個Filter過濾器的作用,。
1、asp.net的HTTP請求處理過程
說明:
(1),、客戶端瀏覽器向服務器發(fā)出一個http請求,,此請求會被inetinfo.exe進程截獲,然后轉交給aspnet_isapi.dll進程,,接著它又通過Http Pipeline的管道,,傳送給aspnet_wp.exe這個進程,接下來就到了.net framework的HttpRunTime處理中心,,處理完畢后就發(fā)送給用戶瀏覽器,。
(2)、當一個http請求被送入到HttpRuntime之后,,這個Http請求會繼續(xù)被送入到一個被稱之為HttpApplication Factory的一個容器當中,,而這個容器會給出一個HttpApplication實例來處理傳遞進來的http請求,而后這個Http請求會依次進入到如下幾個容器中:HttpModule --> HttpHandler Factory --> HttpHandler,。當系統(tǒng)內部的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請求控制權交出,而是繼續(xù)觸發(fā)AcquireRequestState事件以及PreRequestHandlerExcute事件,。在PreRequestHandlerExcute事件之后,,HttpModule窗口就會將控制權暫時交給HttpHandler容器,以便進行真正的HTTP請求處理工作,。
而在HttpHandler容器內部會執(zhí)行ProcessRequest方法來處理HTTP請求,。在容器HttpHandler處理完畢整個HTTP請求之后,,會將控制權交還給HttpModule,HttpModule則會繼續(xù)對處理完畢的HTTP請求信息流進行層層的轉交動作,,直到返回到客戶端為止,。
PS:紅色的HttpApplication實例在HttpModule的Init方法中會用到。
(4)如果想在中途截獲一個httpRequest并做些自己的處理,,就應該在HttpRuntime運行時內部來做到這一點,,確切的說是在HttpModule這個容器中來實現。
2,、HttpModule工作原理
負責監(jiān)聽HttpRequest,同時對HttpRequest增添或者過濾掉一部分內容,。也就是說,,當一個HTTP請求到達HttpModule時,整個ASP.NET Framework系統(tǒng)還并沒有對這個HTTP請求做任何處理,,也就是說此時對于HTTP請求來講,,HttpModule是一個HTTP請求的“必經之路”,所以可以在這個HTTP請求傳遞到真正的請求處理中心(HttpHandler)之前附加一些需要的信息在這個HTTP請求信息之上,,或者針對截獲的這個HTTP請求信息作一些額外的工作,,或者在某些情況下干脆終止?jié)M足一些條件的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
{
public interface IHttpModule
{
// 銷毀不再被HttpModule使用的資源
void Dispose();
// 初始化一個Module,為捕獲HttpRequest做準備
void Init(HttpApplication context);
}
}
下面是自己的HttpModule:
using System;
using System.Web;
namespace ClassLibrary1
{
public class MyHttpModule : IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(Application_BeginRequest);
context.EndRequest += new EventHandler(Application_EndRequest);
}
public void 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 |
從緩存中得到相應時候觸發(fā) |
AcquireRequestState |
加載初始化Session時候觸發(fā) |
PreRequestHandlerExecute |
在Http請求進入HttpHandler之前觸發(fā) |
PostRequestHandlerExecute |
在Http請求進入HttpHandler之后觸發(fā) |
ReleaseRequestState |
存儲Session狀態(tài)時候觸發(fā) |
UpdateRequestCache |
更新緩存信息時觸發(fā) |
EndRequest |
在Http請求處理完成的時候觸發(fā) |
PreSendRequestHenaders |
在向客戶端發(fā)送Header之前觸發(fā) |
PreSendRequestConternt |
在向客戶端發(fā)送內容之前觸發(fā) |
說明:
a,、BenginRequest和EndRequest分別是HttpModule容器最開始的和最后的事件,;
b、EndRequest之后還會觸發(fā)PreSendRequestHeaders事件和PreSendRequestContent事件,,這不是在HttpModule外的兩個事件,,表示HttpModule結束,即將開始向Client發(fā)送數據,。
(2),、驗證HttpModule生命周期
與HttpHandler的交互:
說明:
a,、HttpModule容器會將HttpRequest傳遞到HttpHandler容器,這個時間點是ResolveRequestCache事件
b,、HttpModule容器會建立HttpHandler實例作為入口——Session從此生效
c,、觸發(fā)AcquireRequestState事件以及PreRequestHandlerExecute事件
d、HttpModule容器便將對HttpRequest的控制權轉讓給HttpHandler容器
e,、HttpHandler容器處理HttpRequest——使用自身的ProcessRequest方法,,將對其控制權又還給HttpModule容器——之后Session失效。
驗證生命周期代碼:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace MyHttpModule
{
public class ValidaterHttpModuleEvents : IHttpModule
{
public void Dispose()
{ }
/// <summary>
/// 驗證HttpModule事件機制
/// </summary>
/// <param name="application"></param>
public void Init(HttpApplication application)
{
application.BeginRequest += new EventHandler(application_BeginRequest);
application.EndRequest += new EventHandler(application_EndRequest);
application.AcquireRequestState += new EventHandler(application_AcquireRequestState);
application.AuthenticateRequest += new EventHandler(application_AuthenticateRequest);
application.AuthorizeRequest += new EventHandler(application_AuthorizeRequest);
application.PreRequestHandlerExecute += new EventHandler(application_PreRequestHandlerExecute);
application.PostRequestHandlerExecute += new EventHandler(application_PostRequestHandlerExecute);
application.ReleaseRequestState += new EventHandler(application_ReleaseRequestState);
application.ResolveRequestCache += new EventHandler(application_ResolveRequestCache);
application.PreSendRequestHeaders += new EventHandler(application_PreSendRequestHeaders);
application.PreSendRequestContent += new EventHandler(application_PreSendRequestContent);
}
private void application_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_BeginRequest<br/>");
}
private void application_EndRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_EndRequest<br/>");
}
private void application_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_PreRequestHandlerExecute<br/>");
}
private void application_PostRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_PostRequestHandlerExecute<br/>");
}
private void application_ReleaseRequestState(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_ReleaseRequestState<br/>");
}
private void application_AcquireRequestState(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_AcquireRequestState<br/>");
}
private void application_PreSendRequestContent(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_PreSendRequestContent<br/>");
}
private void application_PreSendRequestHeaders(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_PreSendRequestHeaders<br/>");
}
private void application_ResolveRequestCache(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_ResolveRequestCache<br/>");
}
private void application_AuthorizeRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_AuthorizeRequest<br/>");
}
private void application_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
application.Context.Response.Write("application_AuthenticateRequest<br/>");
}
}
}
<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
{
public void Dispose() { }
public void 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事件,??聪旅娴膱D示: