程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> ASP.NET >> ASP.NET基礎 >> asp.net 請求輸入到輸出的全過程及httpHandler和httpModuler詳細介紹

asp.net 請求輸入到輸出的全過程及httpHandler和httpModuler詳細介紹

編輯:ASP.NET基礎

最近看了幾篇講述httpHandler和HttpModuler的文章,總的來說還是Fish li的那篇文章給力,但是他是大牛,他寫出來的文章技術含量太高,對於像我這樣的小兵,

要完全看懂估計需要看幾遍。雖然說沒有完全了解底層操作,但是我也算明白了一個請求從進入IIS到最後輸出都經歷了哪些過程。說實話,原來我以為.Net的類的子

類都是設計者自己設計的,沒有考慮到真正的程序員是否可以完全掌握。了解了底層操作,我發現我的那個觀點是多麼的無知,每個.Net的類都是對應現實中的一種對

象,比如說Mvc3 中的路由就包括RouteData和HttpContext,至於為什麼要這樣包含?只有了解了iis的觸發過程,我們就會真正的了解了。

序言介紹完畢,現在就來分享一下我對IIS底層的理解。技術不過硬,只能是采用大白話來說。

上面這幅圖說明了在IIS 6 下的處理過程。

因為我們現在所用的是MVC3  ,所以我就按照MVc3 中的生命周期來敘述一個請求從開始到消亡的全過程。

請求階段

  用戶通過浏覽器輸入localhost/home/index 的地址,浏覽器會發送一個請求到服務器的IIS用來處理這個請求。其實在操作系統中存在一個系統文件叫做http.sys

文件,它用來監視是否有請求到來,也就是說一個用戶發來的請求的第一個接待者就是http.sys,它是一個系統文件,運行在操作系統的內核模式下,因此運行速度

更快。

在http.sys文件接收到請求之後(注:這是我的一個理解誤區,我以前一直以為請求會直接進入IIS),會傳入到第二個接待者IIS,真正的用來處理請求的操作系統組

件。在IIS接收到用戶請求以後,首先會通過映射文件  然後由aspnet_iisapi.dll (IIS擴展)根據文件擴展名來選擇對應的應用程序。這樣說有點拗口,直白點的意思

就是IIS擴展會根據傳入文件的擴展名(.aspx等)來選擇 在IIS中配置的處理程序。這裡會有一個問題存在,在Mvc中沒有擴展名,那麼程序是如何匹配的呢?其實這個

問題的處理方法有兩種

  1.就是通過在路由表中添加一個虛擬的擴展名來欺騙IIS

  2.就是通過在IIS配置文件中不選擇確認文件存在,讓IIS根據沒有文件擴展名的文件路徑來進行處理

現在這個請求到了哪裡?到了IIS擴展這裡,下一步就是要進入到.Net框架中,讓.Net框架來處理請求。但是在這中間會經過一些步驟的處理。大家應該記得在Web

form中有很多的事件,Page_load、Page_Render等,這些事件的執行順序是依次進行的,不會混亂?那麼.Net框架是如何來保證這些事件的順序執行呢?這就是今

天的第一個主角HttpModule。我們可以把它稱為http請求的過濾器,因為它不會有任何的輸出,它會在任何請求中都會執行。當然有一個例外,那就是靜態文件或者

其他沒有配置為讓IIS擴展讓.Net框架處理的請求文件,因為他們進入到IIS中,IIS會找到對應的文件然後輸出給浏覽器的。

HttpModule的具體使用大牛們都說的很清楚了,我就簡潔的描述一下大牛們忽略的知識點。既然說HttpModule是一個過濾器,那麼我們可以在任何一個HttpModule

中終止當前請求的執行,執行身份認證,請問文件的訪問權限檢查等操作。我們可以自定義HttpModule擴展,只是讓我們自己定義的類實現IHttpModule接口即可,

在IHttpModule  接口中有一個Init(HttpApplication app)方法,這是我們自定義擴展Module的入口,我們可以在其中定義我們自己進行的處理操作。

Init這個方法會接受一個HttpApplication類型的參數,HttpApplication 在MSDN中的定義就是定義 ASP.NET 應用程序中的所有應用程序對象通用的方法、屬性和事

件。此類是用戶在 global.asax 文件中所定義的應用程序的基類。HttpApplication 類的實例是在 ASP.NET 基礎結構中創建的,而不是由用戶直接創建的。

HttpApplication 類的一個實例在其生存期內被用於處理多個請求,但它一次只能處理一個請求。這樣,成員變量才可用於存儲針對每個請求的數據。

看到這個類的定義我們有沒有想到應用程序池的概念,在IIS中我們新建一個應用程序就會創建一個對應的應用程序池,其實在應用程序池中存儲的是什麼?應該就是

這些HttpApplication對象。每個請求會有一個對應的HttpApplication對象來全程的負責它的執行,在httpApplication對象中包含著請求所需要的所有參數值。例如

Response、Request、Cache等.Net常用的對象,甚至我們可以通過這個變量獲取到web.config中定義的所有Module擴展。HttpApplication會伴隨著請求的全部

執行過程。

現在一個問題又來了,這個Module擴展需要傳遞一個HttpApplication對象作為參數,那麼這個方法的參數是由誰創建的呢?我們應該經常用到一個類

HttpRuntime,根據這個字面意思,我們也可以想到這個就是表示的Http運行時,是的,在IIS將請求的數據准備好以後會通過HttpRuntime 調用

HttpApplicationFactory的一個Create()方法來得到一個HttpApplication對象,然後把參數值傳遞給這個對象,最後這個對象會傳遞到Module擴展中。

現在請求經過了Module擴展過濾之後,就要進入到真正處理它的地方了,HttpHandler,提起它,如果我們有點陌生,那麼我們一定使用過.Net中的一般處理程序,

我們可以看到一般處理程序是一個ashx文件,其中會繼承自IHttpHandler接口,進行ProcessRequest處理。其實我們的HttpHandler就是ashx文件的codeBehind

文件。只要我們實現了IHttpHandler接口中的方法,就定義了一個Handler擴展。

HttpHandler 是作為處理者的角色出現的,不是過濾者,所以Handler會有輸出結果。如果你要在Handler中使用Session,那麼就要繼承IRequiredSessionState

接口,或者加上一個IReadOnlySessionState接口,這樣我們操作Session的時候才不會出現錯誤。在Handler中我們可以進行任何我們想要的操作,例如生成圖片

水印、防盜鏈甚至是文件的輸出壓縮以及編碼等都可以實現。

像我們的Web Service以及一般處理程序,從本質上說都是Handler的一種高層實現方式,都是進行了Handler的擴展操作。

因為我們討論的是MVC,所以我們不得不考慮路由Route,其實Route是Mvc中的一個單獨的組件,它在我們的整個請求中也占據了非常重要的地位。在IIS通過IIS擴

展選擇了適當的處理程序來處理這個請求的時候,就是路由出現的時候,路由會根據路由配置分析這個路徑的ControllerName以及ActionName,對應的參數值,然

後會把這些參數存儲到RouteData中,RouteTable.Routes 是一個路由集合,RouteData和HttpContext上下文就會組成另一個類的對象,RequestContext,我

們在MVC編程的時候,經常會用到這個對象中的一些數據。.Net框架會根據RequestContext對象的值來匹配程序中的Controller以及Action,然後調用

ControllerDescriptor 執行Controller,生成Controller的對象,然後通過ActionInvoke方法來執行具體的Action。

在Action執行完畢,返回對應的視圖的時候,整個請求在.Net框架中的處理就算結束了。在輸出結果返回到用戶浏覽器之前,輸出結果還會經過Module擴展的最後處

理,輸出結果到達IIS,最後IIS通過Http.sys響應到用戶浏覽器上,用戶就可以看到輸出結果。

因為一個請求從進入到顯示在浏覽器上會兩次經過Module擴展,這就是為什麼我們在web form中可以定義一個開始事件,然後還會有一個完成事件的原因。

總結一下,一個用戶發起的請求通過http.sys-->IIS-->aspnet_iisapi.dll-->對應的處理程序-->Module--->Handler-->Module--->IIS-->http.sys-->用戶浏覽器。

當然這個請求的順序不是特別的准確,因為省略了好多的細節,但是從大的方面說就是這些功能。可能你會有一個疑問,aspx文件沒有是什麼時候執行的呢?其實這

個問題我以前也有想過,aspx是在Module之後處理的,但是在handler之後還是之前呢?今天終於得到了答案,其實一個單獨的aspx文件就是一個handler,每個

aspx文件在編譯的時候都會編譯成一個類,這個類繼承自Page,但是Page繼承自哪裡呢?
復制代碼 代碼如下:
public class Page : TemplateControl, IHttpHandler

我們可以看到Page繼承自IHttpHandler接口,這就驗證了Page類的執行是在Handler執行的時候觸發的。

一個小小的http請求會讓我們有那麼多的知識要掌握,我們作為程序員對於這個請求的模型應該是很熟悉。但是作為.Net 拖控件開發的程序員,我善意的提醒一下,

如果可以不用控件,我們就別用了,用js、css來代替吧,畢竟html是基礎。在Mvc時代到來的時候,,擁抱新技術吧。

我是小兵,沒有太多的發言權,所以我就是按小兵的思路來分析大牛們的技術。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved