httpModules與Http模組

weixin_33860553發表於2016-09-24

httpModules是往當前應用程式新增HttpModule(http模組)的標籤。配置節如下

<httpModules>
<add name="ModuleName"
type=".NET Class, Assembly [,Version=version number]
[,Culture=culture] [,PublicKeyToken=token]"/>
<remove... />
<clear/>
</httpModules>

   

提起httpModule不得不提一下Http請求處理流程

ASP.NET對請求處理的過程

當請求一個*.aspx檔案的時候,這個請求會被inetinfo.exe程式截獲,它判斷檔案的字尾(aspx)之後,將這個請求轉交給ASPNET_ISAPI.dll,ASPNET_ISAPI.dll會通過http管道(Http PipeLine)將請求傳送給ASPNET_WP.exe程式,在ASPNET_WP.exe程式中通過HttpRuntime來處理這個請求,處理完畢將結果返回客戶端。

Http 管道

1. HttpRuntimeHttp請求轉交給 HttpApplicationHttpApplication代表著程式設計師建立的Web應用程式。HttpApplication建立針對此Http請求的 HttpContext物件,這些物件包含了關於此請求的諸多其他物件,主要是HttpRequestHttpResponseHttpSessionState等。這些物件在程式中可以通過Page類或者Context類進行訪問。、

2. 接下來Http請求通過一系列Module,這些ModuleHttp請求具有完全的控制權。這些Module可以做一些執行某個實際工作前的事情。

3. Http請求經過所有的Module之後,它會被HttpHandler處理。在這一步,執行實際的一些操作,通常也就是.aspx頁面所完成的業務邏輯。可能你會覺得在建立.aspx頁面並沒有體會到這一過程,但是,你一定知道,.aspx 頁面繼承自Page類,我們看一下Page類的簽名:

public class Page : TemplateControl, IHttpHandler{

    // 程式碼省略

}

 

可以看到,Page類實現了IHttpHandler介面,HttpHandler也是Http請求處理的最底層。

4.HttpHandler處理完以後,Http請求再一次回到Module,此時Module可以做一些某個工作已經完成了之後的事情。

從第二步到第四步可以用下面的圖來展示

 

在http請求的處理過程中,只能呼叫一個HttpHandler,但可以呼叫多個HttpModule。

   

下面則詳細說說HttpModule  

HTTP 模組是一個在每次針對應用程式發出請求時呼叫的程式集。HTTP 模組作為請求管道的一部分呼叫,它們能夠在整個請求過程中訪問生命週期事件。因此,HTTP 模組使您可以檢查傳入的請求並根據該請求進行操作。它們還使您可以檢查傳出的響應並修改它。

ASP.NET HTTP 模組針對所有請求呼叫,這與 ISAPI 篩選器類似。但是它們是用託管程式碼編寫的,而且可以與 ASP.NET 應用程式的生命週期完全整合。可以將自定義模組原始碼放在應用程式的 App_Code 資料夾中,也可以將經過編譯的自定義模組作為程式集放在應用程式的 Bin 資料夾中。

ASP.NET 使用模組來實現各個應用程式功能,其中包括 Forms 身份驗證、快取、會話狀態和客戶端指令碼服務。在每種情況下,如果這些服務處於啟用狀態,模組會作為請求的一部分呼叫,並執行在任何單一頁請求範圍之外的任務。模組可以使用應用程式事件,可能會引發可在 Global.asax 檔案中處理的事件。

功能

模組可以訂閱多種請求管道通知。模組可以接收 HttpApplication 物件的事件通知。

使用場景

HTTP 模組通常具有以下用途:

  • 安全 因為您可以檢查傳入的請求,所以 HTTP 模組可以在呼叫請求頁、XML Web services 或處理程式之前執行自定義的身份驗證或其他安全檢查。在以整合模式執行的 Internet 資訊服務 (IIS) 7.0 中,可以將 Forms 身份驗證擴充套件到應用程式中的所有內容型別。
  • 統計資訊和日誌記錄 因為 HTTP 模組是在每次請求時呼叫的,所以,您可以將請求統計資訊和日誌資訊收集到一個集中的模組中,而不是收集到各頁中。
  • 自定義的頁首或頁尾 因為您可以修改傳出響應,所以可以在每一個頁面或 XML Web services 響應中插入內容,如自定義的標頭資訊。

ASP.NET中一些內建的HttpModule

名稱

型別

功能

OutputCache

System.Web.Caching.OutputCacheModule

頁面級輸出快取

Session

System.Web.SessionState.SessionStateModule

Session狀態管理

WindowsAuthentication

System.Web.Security.WindowsAuthenticationModule

用整合Windows身份驗證進行客戶端驗證

FormsAuthentication

System.Web.Security.FormsAuthenticationModule

用基於Cookie的窗體身份驗證進行客戶端身份驗證

PassportAuthentication

System.Web.Security.PassportAuthenticationModule

MS護照進行客戶身份驗證

RoleManager

System.Web.Security.RoleManagerModule

管理當前使用者角色

UrlAuthorization

System.Web.Security.UrlAuthorizationModule

判斷使用者是否被授權訪問某一URL

FileAuthorization

System.Web.Security.FileAuthorizationModule

判斷使用者是否被授權訪問某一資源

AnonymousIdentification

System.Web.Security.AnonymousIdentificationModule

管理Asp.Net應用程式中的匿名訪問

Profile

System.Web.Profile.ProfileModule

管理使用者檔案檔案的創立及相關事件

ErrorHandlerModule

System.Web.Mobile.ErrorHandlerModule

捕捉異常,格式化錯誤提示字元,傳遞給客戶端程式

   

下面摘抄了MSDN上的一個例子,自定義一個HttpModule

HttpModule必須實現介面System.Web.IHttpModule

 

namespace FastDoge.Study
{
    public class MyModule : IHttpModule
    {
        public void Dispose()
        {
            
        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest +=
            (new EventHandler(this.Application_BeginRequest));
            context.EndRequest +=
                (new EventHandler(this.Application_EndRequest));
        }

        private void Application_BeginRequest(Object source,
        EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            context.Response.Write("<h1><font color=red>" +
                "HelloWorldModule: Beginning of Request" +
                "</font></h1><hr>");
        }

        private void Application_EndRequest(Object source, EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            context.Response.Write("<hr><h1><font color=red>" +
                "HelloWorldModule: End of Request</font></h1>");
        }

    }

在 IIS 6.0 和 IIS 7.0 經典模式下執行的Web.config新增以下配置

 

<configuration>
  <system.web>
    <httpModules>
      <add name="myModule" type="FastDoge.Study.MyModule"/>
     </httpModules>
  </system.web>
</configuration>

由於鄙人用的是IIS7整合模式,配置會不一樣

  <system.webServer>
    <modules>
      <add name="myModule" type="FastDoge.Study.MyModule"/>
    </modules>
  </system.webServer>

 

效果如下所示

當然網站不能是空網站,否則輸出的只是一行

<hr><h1><font color=red>HelloWorldModule: End of Request</font></h1>

的字串。在Init方法中傳入的HttpApplication 物件可以繫結的事件可以參考ASP.NET 應用程式生命週期中提到的,事件一共20幾個。

在網上找了一幅圖,列出了事件觸發的順序

BeginRequest和PreRequestHandlerExecute之間的事件是在伺服器執行HttpHandler處理之前觸發。

    PostRequestHandlerExecute和PreSendRequestContent之間的事件是在伺服器執行Handler處理之後觸發。

可是鄙人糾結的一點在於沒發現某個ASP.NET內建的HttpModule呼叫了Handler。對於ASP.NET WebForm來說,每個Page都是一個Handler。而對ASP.NET MVC來說,在之前看蔣金楠老是的著作時看到的是觸發一個UrlRoutingModule,它在OnPostResolveRequestCache事件中給HttpContext指定了一個MvcHandler。這樣就會使得HttpHandler會被呼叫?或許需要看一下原始碼了。另外還有一個值得學習的地方就是這種模組的新增以及往Application註冊事件的形式,使得HttpApplication具備的較好的靈活性。

在入行之初寫過一篇部落格,就用到HttpModule,當時有位園友評論說可以用Global.asax。結合當時的場景確實如此。但是兩者對比起來肯定有弊有利。

模組相對於 Global.asax 檔案具有如下優點:模組可以進行封裝,因此可以在建立一次後在許多不同的應用程式中使用。

用 Global.asax 檔案的好處在於可以處理其他已註冊事件,如 Session_Start 和 Session_End。此外,Global.asax 檔案還允許您例項化可在整個應用程式中使用的全域性物件。

當您必須建立依賴應用程式事件的程式碼,並且符合以下條件時,都應該使用模組:

  • 希望在其他應用程式中重用該模組。
  • 希望避免將複雜程式碼放在 Global.asax 檔案中。
  • 該模組應用於管道中的所有請求(僅限 IIS 7.0 整合模式)。

當您必須建立依賴應用程式事件的程式碼並且不需要跨應用程式重用程式碼時,應該將程式碼新增到 Global.asax 檔案中。

相關文章