1. 程式人生 > >ASP.NET底層機制 (上) HttpModule

ASP.NET底層機制 (上) HttpModule

 1.ASP時代的HTTP請求處理過程

在IIS的應用程式對映中,IIS會將對asp和asa檔案的請求轉交給asp.dll這個ISAPI來處理

Inetinfo.exe程序,即www服務程序
解釋型處理,每次請求都會重新解釋一次,不適用於大流量請求

2.ASP.NET的HTTP請求處理過程



3.在HttpRuntime中請求處理過程
HttpRequest請求:
進入HttpRumtime——通過HttpApplicationFactory,建立HttpApplication例項——進入HttpModule——通過HttpHandlerFactory,建立HttpHandler例項
    *這個HttpApplication例項在HttpModule的Init方法中會用到

4.HttpModule工作原理
負責監聽HttpRequest,同時對HttpRequest增添或者過濾掉一部分內容。
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;


IHttpModule介面分析:

publicinterface IHttpModule
{
    
// 銷燬不再被HttpModule使用的資源
void Dispose();

    
//初始化一個Module,為捕獲HttpRequest做準備
void Init(HttpApplication context);
}


編寫自己的HttpModule:

//注意要在這個類庫中新增System.Web引用
using System;
using System.Web;

namespace ClassLibraryModule
{
    
publicclass MyHttpModule : IHttpModule
    
{
        
publicvoid Init(HttpApplication context)
        
{
            context.BeginRequest 
+=new EventHandler(this.Application_BeginRequest);
            context.EndRequest 
+=new EventHandler(this.Application_EndRequest);
        }


        
publicvoid Dispose() { }


        
//自己要處理私事的兩個方法
publicvoid Application_BeginRequest(Object sender, EventArgs e)
        
{
            HttpApplication application 
= (HttpApplication)sender;

            HttpContext context 
= application.Context;
            HttpResponse response 
= application.Response;
            HttpRequest request 
= application.Request;

            response.Write(
"來自Application_BeginRequest");
        }


        
publicvoid Application_EndRequest(Object sender, EventArgs e)
        
{
            HttpApplication application 
= (HttpApplication)sender;

            HttpContext context 
= application.Context;
            HttpResponse response 
= application.Response;
            HttpRequest request 
= application.Request;

            response.Write(
"來自Application_EndRequest");
        }

    }

}


在Web專案中新增這個類庫的引用,同時在Web.config的system.web標籤中新增:

<httpModules>
            
<add name="Test" type="ClassLibraryModule.MyHttpModule,ClassLibraryModule"></add>
        
</httpModules>

name可以隨意指定,沒有影響。
type有兩個引數,第一個表示具體哪個類,第二個表示是哪個dll

不需要在Web專案新增對類庫的引用,只是複製一份到bin目錄下即可

於是該站點下的每個頁面都會Response.Write兩句話——這適合做廣告,只要替換成javascript即可

5.HttpModule內部事件機制
HttpApplication例項有很多事件,BenginRequest和EndRequest分別是HttpModule容器最開始的和最後的事件

注意,EndRequest之後還會觸發PreSendRequestHeaders事件和PreSendRequestContent事件,這不是在HttpModule外的兩個事件,表示HttpModule結束,即將開始向Client傳送資料。

HttpModule容器與HttpHandler容器的互動:
    HttpModule容器會將HttpRequest傳遞到HttpHandler容器,這個時間點是ResolveRequestCache事件。
    HttpModule容器會建立HttpHandler例項作為入口——Session從此生效
    觸發AcquireRequestState事件以及PreRequestHandlerExecute事件,
    HttpModule容器便將對HttpRequest的控制權轉讓給HttpHandler容器。
    HttpHandler容器處理HttpRequest——使用自身的ProcessRequest方法,將對其控制權又還給HttpModule容器——之後Session失效


可以同時載入兩個HttpModule,

<httpModules><add name="Test1" type="ClassLibraryModule.MyHttpModule1,ClassLibraryModule1"></add><add name="Test2" type="ClassLibraryModule.MyHttpModule2,ClassLibraryModule2"></add></httpModules>

這時,根據add標籤的先後,依次執行:
    Test1.BeginRequest
    Test2.BeginRequest
    .....
    Test1.EndRequest
    Test2.EndRequest

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

publicvoid Application_BeginRequest(Object sender, EventArgs e)
        
{
            HttpApplication application 
= (HttpApplication)sender;
            HttpContext context 
= application.Context;

            application.CompleteRequest();

            context.Response.StatusCode 
=500;
            context.Response.StatusDescription 
="Internal Server Error";
        }

在BeginRquest中終止,但是仍然會呼叫EndRequest事件,以及PreSendRequestHeaders事件和PreSendRequestContent事件——應該說直接跳轉到EndRequest事件,而不會呼叫這期間的事件
如果有兩個HttpModule,在第一個Module的BeginRequest中終止,僅僅不會呼叫第二個Module的BeginRequest,但仍然會呼叫兩個EndRequest事件,以及PreSendRequestHeaders事件和PreSendRequestContent事件。

以上兩句話,可以用下圖來表示: