天天看點

ASP.NET 中Http處理流程與 HttpModule,HttpHandler學習之初步認知

本文隻是對HttpModule和HttpHandler做最初步的了解。非菜鳥級别人士可直接無視。

ASP.NET 中Http的請求流程   

1. 使用者發出的用戶端請求達到伺服器後,會被服務端的inetinfo.exe 程序捕獲,該程序将該http請求轉交給asp.net_isapi.dll程序,然後通過http pipeline 管道(具體這是什麼東西我也不清楚)傳送給aspnet_wp.exe程序來處理。接下來就到了.net framework的httpruntime進行中心,處理完畢後,就發送給使用者的浏覽器。

2. 當http請求傳送給httpruntime 的時候,首先會進入一個叫做HttpApplication Factory的容器之中,從這個名字上很容易看出是一個工廠,該工廠産生一個HttpApplication的執行個體,該執行個體儲存有該請求的所有資訊。然後,http請求進入HttpModule容器之中,然後進入HttpHandlerFactory中,調用相應的HttpHandler,執行其ProcessRequest方法,完成整個請求的處理。其中httpHandler是真正的請求進行中心。Httpmodule隻是在該進行中心做處理之前對其進行一些額外的處理,篩選等等。

3. 大體的流程如下所示

ASP.NET 中Http處理流程與 HttpModule,HttpHandler學習之初步認知

HttpRequest------ inetinfo.exe--- aspnet_isapi.dll ---- http pipeline --aspnet_wp.exe ---http runtime----Http Application ---Http Application ---HttpModule---HttpHandler Factory ---HttpHandler -----HttpHandler.Process Request()

以上内容大多取自【我也想飛翔-tangself】的HttpModule的認識一文,大家可以 看原作: http://www.cnblogs.com/tangself/archive/2011/03/28/1998007.html

4. 執行ProcessRequest 的過程其實也就是整個ASP.NET page 頁面的生命周期。

ASP.NET 的Page類實作了IHttpHandler,而我們每一個頁面都是繼承與Page的,那麼也就是說每一個頁面都是一個HttpHandler,這個Handler就會處理目前頁面的請求。看來,應該是預設将該Handler和該頁面路徑比對起來。這個我沒有考證,隻是我的推測。

ProcessRequest 首先會調用this.FrameworkInitialize(); 以建構控件樹。然後預初始化OnPreInit,然後 調用PerformPreInit()完成預初始化,然後開始初始化Init(),注意執行初始化的時候 已經執行了TraceViewState ,已經開始對資料進行了跟蹤,如果資料成為dirty資料,則會被存儲到statebag中。具體什麼時候開啟的,我現在還不太清楚。接下來,如果是回傳,則會加載控件的頁面視圖狀态,處理回傳資料(ProcessPostData) ,如果是第一加載,則會跳過這一部分。随後執行預加載操作OnPreLoad,然後執行OnLoad(LoadRecursive)。如果是回傳,會發送回傳變化通知,處理回傳事件方法RaisePostbackEvent。随後執行OnLoadCompleted 。接下來進入預呈現OReRender,儲存個性化資料和視圖狀态(所謂的視圖狀态儲存,在這個部分實際上就是調用SaveState,将原有的鍵值對資料儲存到一個ArrayList中,序列化輸出到頁面上是之後的事情了)。然後執行呈現方法Render,随後頁面加載完畢執行OnUnload操作。

ASP.NET 中Http處理流程與 HttpModule,HttpHandler學習之初步認知

更加詳細可靠的内容大家可以移步這裡

1. ASP.NET程式設計模型之ASP.NET頁面生命周期圖解 http://developer.51cto.com/art/200908/141235.htm

2. ASP.NET VIEW STATE 詳解(講的很詳細,由淺入深,老外的。。。)

http://www.cnblogs.com/xianrongbin/articles/2240851.html

HttpModule初步接觸            

我們可以實作自己的HttpModule,隻要繼承IHttpModule即可。

IHttpModul接口如下

Using System;
Namespace System.Web
{
Public interface IHttpModule
{
// 銷毀不再被HttpModule使用的資源
void Dispose();
// 初始化一個Module,為捕獲HttpRequest做準備
void Init(HttpApplication context);
{}
}
           

下面是我自己寫的Module,實際上和 http://www.cnblogs.com/tangself/archive/2011/03/28/1998007.html差不多。。。

public class MyHttpModule:IHttpModule
{
	public MyHttpModule()
	{

	}
    public void Dispose()
    {

    }

    /// <summary>
    /// 準備初始化一個module,為截獲httprequest做準備
    /// </summary>
    /// <param name="context"></param>
    public void Init(HttpApplication context)
{
		//通過兩個事件訂閱,加入自己的處理
        context.BeginRequest+=new EventHandler(this.Application_BeginReqest);
        context.EndRequest+=new EventHandler(this.Application_EndReqest);
    }

    public void Application_BeginReqest(object  sender,EventArgs e)
    {
        HttpApplication app = sender as HttpApplication;
        if(app!=null)
        {
            HttpContext context = app.Context;
            context.Response.Write("this is in  module begin request ");
        }
    }

    public void Application_EndReqest(object sender, EventArgs e)
    {
        HttpApplication httpApp = sender as HttpApplication;
        if(httpApp!=null)
        {
            HttpContext context = httpApp.Context;
            context.Response.Write("this is in module end request");
        }
    }
}
           

這個類我建在了AppCode中,是以預設沒有名空間

然後在web.config的system.web節點下添加如下配置

<httpModules>
<add name="myHttpModule" type="MyHttpModule"/>
</httpModules>
           

建立hellomodule頁面,通路,頁面輸出如下

ASP.NET 中Http處理流程與 HttpModule,HttpHandler學習之初步認知

可以看出請求該頁面前先執行了該Module中的方法。然後才轉交給了頁面這個HttpHandler。如果沒有這個頁面,我們随便通路一個位址,那麼就會資源未找到的錯誤。

我們在建立一個HttpModule跟原來的一樣,隻不過命名為HttpModule2,添加配置。

<httpModules>
<!--<先會經過這個鍊式的module>-->
<add name="myHttpModule" type="MyHttpModule"/>
<add name="myHttpModule2" type="MyHttpModule2"/>
</httpModules>
           

通路頁面可以發現,整個請求過程中先經過了myHttpModule 處理,在經過了myHttpModule1的處理。

注:type字段填寫的是該module的名空間.類名,這樣,就可以通過反射的方式進行調用。其實這也就是以來注入吧。

接下來我們在大概看一下HttpHandler

HttpHandler初步接觸   

我們也可以實作自己的HttpHandler。隻要繼承IHttpHandler即可。

IHttpHandler定義如下

public interface IHttpHandler
{
// Methods
void ProcessRequest(HttpContext context);

// Properties
bool IsReusable { get; }
}
           

下邊是我自己實作的HttpHandler

public class MyHandler : IHttpHandler
    {
        public MyHandler()
        {
        }

        /// <summary>
        /// 根據webconfig中的httpHandler節點的path的配置,當通路該節點時,就會自動生成相應的type執行個體,調用該handler的
        /// ProcessRequest方法
        /// 是以,我們可以通過解析路徑的方法,讓路徑對應一個handler中的某個方法,可以使用發射工廠
        /// </summary>
        /// <param name="context"></param>
        public void ProcessRequest(HttpContext context)
        {
           Uri uri= context.Request.Url;
            context.Response.Write("<br/>"+uri.OriginalString);
            context.Response.Write("<br/><h1>Hello,this is my http handler</h1>");
        }

        public bool IsReusable
        {
            get { return true; }
        }
}
           

然後在配置檔案中添加如下配置

<httpHandlers>
<!--處理該aspx終點的輸入請求為保留檔案夾app_code中,程式集的定義可忽略 -->
<add verb="*" path="HelloHandler" type="MyHandler"/>
</httpHandlers>
           

然後在浏覽器中通路HelloHandler,如下所示

ASP.NET 中Http處理流程與 HttpModule,HttpHandler學習之初步認知

我們也可以将該path對應一個aspx頁面,當然這樣就像是給這個路徑指定了兩個HttpHandler。建立一個HelloHandler.aspx頁面,添加内容【 this is in page!!!!!!!!!!!】,然後添加web.Config的Handler配置,我們看看效果

ASP.NET 中Http處理流程與 HttpModule,HttpHandler學習之初步認知

看來page對應的Handler沒有生效。。。。

HttpHandler和HttpModule小小總結

在回過頭來想,最初那個Page Resource Not Fond 的錯誤,其實并不是 Page Not Found而是請求路徑對應的HttpHandler并沒有找到。例如我們在配置檔案做如下配置

<httpHandlers>
<!--處理該aspx終點的輸入請求為保留檔案夾app_code中,程式集的定義可忽略 -->
<add verb="*" path="HelloHandler.aspx" type="MyHandler"/>
<add verb="*" path="my" type="MyHandler"/>
</httpHandlers>
<httpModules>
<!--<先會經過這個鍊式的module>-->
<add name="myHttpModule" type="MyHttpModule"/>
<add name="myHttpModule2" type="MyHttpModule2"/>
</httpModules>
           

請求http://localhost:1684/HandlerStudy/my

輸出内容如下

ASP.NET 中Http處理流程與 HttpModule,HttpHandler學習之初步認知

可以看出來,仍然先經過了連個Module的處理,伺服器認為該路徑對應是有資源的,并沒有出現Page not found 的錯誤。然後,找到該路徑所配置的HttpHandler 執行相應的ProcesRequest方法。

那麼綜合前邊Asp.net 流程的分析,我們就不難得出 如下結論。

當Http 請求進入到HttpRuntime 時,首先會交由一個HttpModule的處理鍊一次處理,處理先後順序和配置順序一緻(其實也應該是事件訂閱的先後順序),該HttpModule處理完畢後,HttpHandler Factory 會擷取所有注入的HttpHandler,根據路徑比對出相應的Handler,利用反射生成相應Handler執行個體,調用相應ProcessRequest方法。

檢視PageHandlerFactory 代碼發現

public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path)
{
return this.GetHandlerHelper(context, requestType, VirtualPath.CreateNonRelative(virtualPath), path);
}

private IHttpHandler GetHandlerHelper(HttpContext context, string requestType, VirtualPath virtualPath, string physicalPath)
{
Page page = BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page), context, true) as Page;
if (page == null)
{
return null;
}
page.TemplateControlVirtualPath = virtualPath;
return page;
}
           

應該基本上就是這樣。

Ok,關于HttpHandler和HttpModule的初步學習就這麼多。對其二者的使用還需要做進一步深入了解。還有就是Page 本身也是一個Handler,是在什麼時候,又是如何注冊到Handler Factory中的,這個問題也需要查一下。

繼續閱讀