ASP.NET對請求處理的過程:

來源:互聯網
上載者:User

ASP.NET對請求處理的過程:
當請求一個*.aspx檔案的時候,這個請求會被inetinfo.exe進程截獲,它判斷檔案的尾碼(aspx)之後,將這個請求轉交給ASPNET_ISAPI.dll,ASPNET_ISAPI.dll會通過http管道(Http PipeLine)將請求發送給ASPNET_WP.exe進程,在ASPNET_WP.exe進程中通過HttpRuntime來處理這個請求,處理完畢將結果返回用戶端。
    inetinfo.exe進程:是www服務的進程,IIS服務和ASPNET_ISAPI.DLL都寄存在此進程中。
    ASPNET_ISAPI.DLL:是處理.aspx檔案的win32組件。其實IIS伺服器是只能識別.html檔案的,當IIS伺服器發現被請求的檔案是.aspx檔案時,IIS伺服器將其交給aspnet_isapi.dll來處理。
    aspnet_wp.exe進程:ASP.NET架構進程,提供.net啟動並執行託管環境,.net的CLR(通用語言執行平台)就是寄存在此進程中。

ASP.NET Framework處理一個Http Request的流程:
    HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->ASPNET_WP.exe-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()

ASP.NET請求處理過程是基於管道模型的,這個管道模型是由多個HttpModule和HttpHandler組成,ASP.NET把http請求依次傳遞給管道中各個HttpModule,最終被HttpHandler處理,處理完成後,再次經過管道中的HTTP模組,把結果返回給用戶端。我們可以在每個HttpModule中都可以幹預請求的處理過程。

注意:在http請求的處理過程中,只能調用一個HttpHandler,但可以調用多個HttpModule。
當請求到達HttpModule的時候,系統還沒有對這個請求真正處理,但是我們可以在這個請求傳遞到處理中心(HttpHandler)之前附加一些其它資訊,或者截獲的這個請求並作一些額外的工作,也或者終止請求等。在HttpHandler處理完請求之後,我們可以再在相應的HttpModule中把請求處理的結果進行再次加工返回用戶端。

HttpModule
    HTTP模組是實現了System.Web.IhttpModule介面的類。
    IHttpModule介面的聲明:
        public interface IHttpModule
        {
            void Init (HttpApplication context);
            void Dispose ();
        }
        Init 方法:系統初始化的時候自動調用,這個方法允許HTTP模組向HttpApplication 對象中的事件註冊自己的事件處理常式。
        Dispose方法: 這個方法給予HTTP模組在對象被垃圾收集之前執行清理的機會。此方法一般無需編寫代碼。
   
    HTTP模組可以向System.Web.HttpApplication對象註冊下面一系列事件:
        AcquireRequestState 當ASP.NET運行時準備好接收當前HTTP請求的對話狀態的時候引發這個事件。
        AuthenticateRequest 當ASP.NET 運行時準備驗證使用者身份的時候引發這個事件。
        AuthorizeRequest 當ASP.NET運行時準備授權使用者訪問資源的時候引發這個事件。
        BeginRequest 當ASP.NET運行時接收到新的HTTP請求的時候引發這個事件。
        Disposed 當ASP.NET完成HTTP請求的處理過程時引發這個事件。
        EndRequest 把響應內容發送到用戶端之前引發這個事件。
        Error 在處理HTTP請求的過程中出現未處理異常的時候引發這個事件。
        PostRequestHandlerExecute 在HTTP處理常式結束執行的時候引發這個事件。
        PreRequestHandlerExecute 在ASP.NET開始執行HTTP請求的處理常式之前引發這個事件。在這個事件之後,ASP.NET 把該請求轉寄給適當的HTTP處理常式。
        PreSendRequestContent 在ASP.NET把響應內容發送到用戶端之前引發這個事件。這個事件允許我們在內容到達用戶端之前改變響應內容。我們可以使用這個事件給頁面輸出添加用於所有頁面的內容。例如通用菜單、頭資訊或腳資訊。
        PreSendRequestHeaders 在ASP.NET把HTTP回應標頭資訊發送給用戶端之前引發這個事件。在頭資訊到達用戶端之前,這個事件允許我們改變它的內容。我們可以使用這個事件在頭資訊中添加cookie和自訂資料。
        ReleaseRequestState 當ASP.NET結束所搜有的請求處理常式執行的時候引發這個事件。
        ResolveRequestCache 我們引發這個事件來決定是否可以使用從輸出緩衝返回的內容來結束請求。這依賴於Web應用程式的輸出緩衝時怎樣設定的。
        UpdateRequestCache 當ASP.NET完成了當前的HTTP請求的處理,並且輸出內容已經準備好添加給輸出緩衝的時候,引發這個事件。這依賴於Web應用程式的輸出緩衝是如何設定的。

    上面這麼多的事件,我們看起來可能會有些眼暈,但沒關係,下面一步一步地看。
    HttpModule生命週期

    下面是事件的觸發順序:

    BeginRequest和PreRequestHandlerExecute之間的事件是在伺服器執行HttpHandler處理之前觸發。
    PostRequestHandlerExecute和PreSendRequestContent之間的事件是在伺服器執行Handler處理之後觸發。
   
    下面我們看一下如何使用HttpModule來實現我們日常的應用:
        HttpModule通過在某些事件中註冊,把自己插入ASP.NET請求處理管道。當這些事件發生的時候,ASP.NET調用對相應的HTTP模組,這樣該模組就能處理請求了。
       1、向每個頁面動態添加一些備忘或說明性的文字:
            有的網站每一個頁面都會彈出一個廣告或在每個頁面都以注釋形式(<!-- -->)加入網站的著作權資訊。如果在每個頁面教編寫這樣的JS代碼的話,對於大一點的網站,這種JS代碼的編寫與維護可是一個很繁瑣枯燥的工作。
            有了HttpModule我們就可以很簡單地解決這個問題了。HttpModule是用戶端發出請求到用戶端接收到伺服器響應之間的一段必經之路。我們完全可以在伺服器處理完請求之後,並在向用戶端發送響應文本之前這段時機,把這段注釋文字添加到頁面文本之後。這樣,每一個頁面請求都會被附加上這段注釋文字。
            這段代碼究竟該在哪個事件裡實現呢? PostRequestHandlerExecute和PreSendRequestContent之間的任何一個事件都可以,但我比較喜歡在EndRequest事件裡編寫代碼。
            第一步:建立一個類庫ClassLibrary831。
            第二步:編寫一個類實現IHttpModule介面
                class TestModule:IHttpModule
                {
                    public void Dispose()
                    {
                    }
                    public void Init(HttpApplication context)
                    {
                    }
                }
            第三步:在Init事件中註冊EndRequest事件,並實現事件處理方法
               class TestModule:IHttpModule
                {
                    public void Dispose(){}
                    public void Init(HttpApplication context)
                    {
                        context.EndRequest += new EventHandler(context_EndRequest);
                    }
                    void context_EndRequest(object sender, EventArgs e)
                    {
                        HttpApplication ha = (HttpApplication)sender;
                        ha.Response.Write("<!--這是每個頁面都會動態產生的文字。--grayworm-->");
                    }
                }
            第四步:在Web.Conofig中註冊一下這個HttpModule模組
          <httpModules>
           <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
          </httpModules>
          name:模組名稱,一般是類名
          type:有兩部分組成,前半部分是命名空間和類名組成的全名,後半部分是程式集名稱,如果類是直接放在App_Code檔案夾中,那程式名稱是App_Code。
                這樣在Web網站是添加該類庫的引用後,運行每個頁面,會發現其源檔案中都會加入“<!--這是每個頁面都會動態產生的文字。--grayworm-->”這句話。同樣的方法你也可以在其中加入JS代碼。
       2、身份檢查
            大家在作登入時,登入成功後,一般要把使用者名稱放在Session中儲存,在其它每一個頁面的Page_Load事件中都檢查Session中是否存在使用者名稱,如果不存在就說明使用者未登入,就不讓其訪問其中的內容。
            在比較大的程式中,這種做法實在是太笨拙,因為你幾乎要在每一個頁面中都加入檢測Session的代碼,導致難以開發和維護。下面我們看看如何使用HttpModule來減少我們的工作量
            由於在這裡我們要用到Session中的內容,我們只能在AcquireRequestState和PreRequestHandlerExecute事件中編寫代碼,因為在HttpModule中只有這兩事件中可以訪問Session。這裡我們選擇PreRequestHandlerExecute事件編寫代碼。
            第一步:建立一個類庫ClassLibrary831。
            第二步:編寫一個類實現IHttpModule介面
                class TestModule:IHttpModule
                {
                    public void Dispose()
                    {
                    }
                    public void Init(HttpApplication context)
                    {
                    }
                }
            第三步:在Init事件中註冊PreRequestHandlerExecute事件,並實現事件處理方法
               class AuthenticModule:IHttpModule
                {
                    public void Dispose(){}
                    public void Init(HttpApplication context)
                    {
                        context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
                    }
                    void context_PreRequestHandlerExecute(object sender, EventArgs e)
                    {
                        HttpApplication ha = (HttpApplication)sender;
                        string path = ha.Context.Request.Url.ToString();
                        int n = path.ToLower().IndexOf("Login.aspx");
                        if (n == -1) //是否是登入頁面,不是登入頁面的話則進入{}
                        {
                            if (ha.Context.Session["user"] == null) //是否Session中有使用者名稱,若是空的話,轉向登入頁。
                            {
                                ha.Context.Response.Redirect("Login.aspx?source=" + path);
                            }
                        }
                    }
                }
            第四步:在Login.aspx頁面的“登入”按鈕中加入下面代碼
                protected void Button1_Click(object sender, EventArgs e)
                {
                    if(true)    //判斷使用者名稱密碼是否正確
                    {
                        if (Request.QueryString["source"] != null)
                        {
                            string s = Request.QueryString["source"].ToLower().ToString();   //取出從哪個頁面轉來的
                            Session["user"] = txtUID.Text;
                            Response.Redirect(s); //轉到使用者想去的頁面
                        }
                        else
                        {
                            Response.Redirect("main.aspx");    //預設轉向main.aspx
                        }
                    }
                }
            第五步:在Web.Conofig中註冊一下這個HttpModule模組
          <httpModules>
           <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
          </httpModules>
       3、多模組的操作
            如果定義了多個HttpModule,在web.config檔案中引入自訂HttpModule的順序就決定了多個自訂HttpModule在處理一個HTTP請求的接管順序。
            

HttpHandler
    HttpHandler是HTTP請求的處理中心,真正地對用戶端請求的伺服器頁面做出編譯和執行,並將處理過後的資訊附加在HTTP請求資訊流中再次返回到HttpModule中。
    HttpHandler與HttpModule不同,一旦定義了自己的HttpHandler類,那麼它對系統的HttpHandler的關係將是“覆蓋”關係。
    IHttpHandler介面聲明
    public interface IHttpHandler
    {
        bool IsReusable { get; }
        public void ProcessRequest(HttpContext context); //請求處理函數
    }
   
    樣本:把硬碟上的圖片以流的方式寫在頁面上
        class TestHandler : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
                byte[] b = new byte[fs.Length];
                fs.Read(b, 0, (int)fs.Length);
                fs.Close();
                context.Response.OutputStream.Write(b, 0, b.Length);
            }
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
        }
        Web.Config設定檔
      <httpHandlers>
       <add verb="*" path="*" type="ClassLibrary831.TestHandler,ClassLibrary831"></add>
      </httpHandlers>
           Verb屬性:指定了處理常式支援的HTTP動作。*-支援所有的HTTP動作;“GET”-支援Get操作;“POST”-支援Post操作;“GET, POST”-支援兩種操作。
  Path屬性:指定了需要調用處理常式的路徑和檔案名稱(可以包含萬用字元)。“*”、“*.aspx”、“showImage.aspx”、“test1.aspx,test2.aspx”
  Type屬性:用名字空間、類名稱和程式集名稱的組合形式指定處理常式或處理常式工廠的實際類型。ASP.NET運行時首先搜尋bin目錄中的DLL,接著在GAC中搜尋。
        這樣程式啟動並執行效果是該網站的任何一個頁面都會顯示worm.jpg圖片。如何只讓一個頁面(default21.aspx)執行HttpHandler中的ProcessRequest方法呢?最簡單的辦法是在Web.Config檔案中把path配置資訊設為default21.aspx。
        根據這個例子大家可以考慮一下如何編寫“驗證碼”了。

IHttpHandler工廠
    IHttpHandlerFactory的作用是對IHttpHandler進行管理。工廠的作用請見http://hi.baidu.com/grayworm/blog/item/4a832160f8c9de46eaf8f8c1.html"
    IHttpHandlerFactory介面的聲明:
        public interface IHttpHandlerFactory
        {
            IHttpHandler GetHandler (HttpContext context,string requestType,string url,string pathTranslated);
            void ReleaseHandler (IHttpHandler handler);
        }
       GetHandler返回實現IHttpHandler介面的類的執行個體,ReleaseHandler使工廠可以重用現有的處理常式執行個體。
    樣本:兩個用IHttpHandlerFactory來實現對不同HttpHandler的調用。
    有兩個HttpHandler:將圖片顯示在頁面上的HttpHandler和產生驗證碼的Handler
        //將圖片顯示在頁面上的Handler
        class TestHandler : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
                byte[] b = new byte[fs.Length];
                fs.Read(b, 0, (int)fs.Length);
                fs.Close();
                context.Response.OutputStream.Write(b, 0, b.Length);
            }
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
        }
        //產生驗證碼的Handler
        class CodeHandler:IHttpHandler
        {
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
            public void ProcessRequest(HttpContext context)
            {
                Image b = new Bitmap(50,20);
                Graphics g = Graphics.FromImage(b);
                SolidBrush sb = new SolidBrush(Color.White);
                Font f = new Font("宋體", 12);
                string str = "";
                Random r = new Random();
                for (int i = 0; i < 4; i++)
                {
                    str += r.Next(10);
                }
                g.DrawString(str,f,sb,0,0);
                b.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
        }
         IHttpHandler工廠
         class TestHandlerFactory : IHttpHandlerFactory
         {
            public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
            {
               
                string fname = url.Substring(url.IndexOf('/') + 1);
                while (fname.IndexOf('/') != -1)
                    fname = fname.Substring(fname.IndexOf('/') + 1);
                string cname = fname.Substring(0, fname.IndexOf('.'));
                string className ="";

                className = "ClassLibrary831.CodeHandler";
                object h = null;
                try
                {
                    //h = new TestHandler();
                    h = Activator.CreateInstance(Type.GetType(className));
                }
                catch (Exception e)
                {
                    throw new HttpException("工廠不能為類型" + cname + "建立執行個體。", e);
                }
                return (IHttpHandler)h;
            }
            public void ReleaseHandler(IHttpHandler handler)
            {
            }
         }(車延祿)
        設定檔
    <httpHandlers>
    <add verb="*" path="default21.aspx,default22.aspx" type="ClassLibrary831.TestHandlerFactory,ClassLibrary831"></add>
   </httpHandlers>
   這樣TestHandlerFactory就會根據請求的不同頁面執行不同的HttpHandler處理常式了。

HttpHandler使用會話
    如果要在處理常式中使用Session,那必須把該HttpHandler實現IRequiresSessionState介面,,IRequiresSessionState介面是個空介面,它沒有抽象方法,只是一個標記。此處就不作例子驗證了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.