最近看了幾篇講述httpHandler和HttpModuler的文章,總的來(lái)說(shuō)還是Fish li的那篇文章給力,但是他是大牛,他寫出來(lái)的文章技術(shù)含量太高,對(duì)于像我這樣的小兵,
要完全看懂估計(jì)需要看幾遍。雖然說(shuō)沒(méi)有完全了解底層操作,但是我也算明白了一個(gè)請(qǐng)求從進(jìn)入IIS到最后輸出都經(jīng)歷了哪些過(guò)程。說(shuō)實(shí)話,原來(lái)我以為.Net的類的子
類都是設(shè)計(jì)者自己設(shè)計(jì)的,沒(méi)有考慮到真正的程序員是否可以完全掌握。了解了底層操作,我發(fā)現(xiàn)我的那個(gè)觀點(diǎn)是多么的無(wú)知,每個(gè).Net的類都是對(duì)應(yīng)現(xiàn)實(shí)中的一種對(duì)
象,比如說(shuō)Mvc3 中的路由就包括RouteData和HttpContext,至于為什么要這樣包含?只有了解了iis的觸發(fā)過(guò)程,我們就會(huì)真正的了解了。
序言介紹完畢,現(xiàn)在就來(lái)分享一下我對(duì)IIS底層的理解。技術(shù)不過(guò)硬,只能是采用大白話來(lái)說(shuō)。

上面這幅圖說(shuō)明了在IIS 6 下的處理過(guò)程。
因?yàn)槲覀儸F(xiàn)在所用的是MVC3 ,所以我就按照MVc3 中的生命周期來(lái)敘述一個(gè)請(qǐng)求從開(kāi)始到消亡的全過(guò)程。
請(qǐng)求階段:
用戶通過(guò)瀏覽器輸入localhost/home/index 的地址,瀏覽器會(huì)發(fā)送一個(gè)請(qǐng)求到服務(wù)器的IIS用來(lái)處理這個(gè)請(qǐng)求。其實(shí)在操作系統(tǒng)中存在一個(gè)系統(tǒng)文件叫做http.sys
文件,它用來(lái)監(jiān)視是否有請(qǐng)求到來(lái),也就是說(shuō)一個(gè)用戶發(fā)來(lái)的請(qǐng)求的第一個(gè)接待者就是http.sys,它是一個(gè)系統(tǒng)文件,運(yùn)行在操作系統(tǒng)的內(nèi)核模式下,因此運(yùn)行速度
更快。
在http.sys文件接收到請(qǐng)求之后(注:這是我的一個(gè)理解誤區(qū),我以前一直以為請(qǐng)求會(huì)直接進(jìn)入IIS),會(huì)傳入到第二個(gè)接待者IIS,真正的用來(lái)處理請(qǐng)求的操作系統(tǒng)組
件。在IIS接收到用戶請(qǐng)求以后,首先會(huì)通過(guò)映射文件 然后由aspnet_iisapi.dll (IIS擴(kuò)展)根據(jù)文件擴(kuò)展名來(lái)選擇對(duì)應(yīng)的應(yīng)用程序。這樣說(shuō)有點(diǎn)拗口,直白點(diǎn)的意思
就是IIS擴(kuò)展會(huì)根據(jù)傳入文件的擴(kuò)展名(.aspx等)來(lái)選擇 在IIS中配置的處理程序。這里會(huì)有一個(gè)問(wèn)題存在,在Mvc中沒(méi)有擴(kuò)展名,那么程序是如何匹配的呢?其實(shí)這個(gè)
問(wèn)題的處理方法有兩種:
1.就是通過(guò)在路由表中添加一個(gè)虛擬的擴(kuò)展名來(lái)欺騙IIS
2.就是通過(guò)在IIS配置文件中不選擇確認(rèn)文件存在,讓IIS根據(jù)沒(méi)有文件擴(kuò)展名的文件路徑來(lái)進(jìn)行處理
現(xiàn)在這個(gè)請(qǐng)求到了哪里?到了IIS擴(kuò)展這里,下一步就是要進(jìn)入到.Net框架中,讓.Net框架來(lái)處理請(qǐng)求。但是在這中間會(huì)經(jīng)過(guò)一些步驟的處理。大家應(yīng)該記得在Web
form中有很多的事件,Page_load、Page_Render等,這些事件的執(zhí)行順序是依次進(jìn)行的,不會(huì)混亂?那么.Net框架是如何來(lái)保證這些事件的順序執(zhí)行呢?這就是今
天的第一個(gè)主角HttpModule。我們可以把它稱為http請(qǐng)求的過(guò)濾器,因?yàn)樗粫?huì)有任何的輸出,它會(huì)在任何請(qǐng)求中都會(huì)執(zhí)行。當(dāng)然有一個(gè)例外,那就是靜態(tài)文件或者
其他沒(méi)有配置為讓IIS擴(kuò)展讓.Net框架處理的請(qǐng)求文件,因?yàn)樗麄冞M(jìn)入到IIS中,IIS會(huì)找到對(duì)應(yīng)的文件然后輸出給瀏覽器的。
HttpModule的具體使用大牛們都說(shuō)的很清楚了,我就簡(jiǎn)潔的描述一下大牛們忽略的知識(shí)點(diǎn)。既然說(shuō)HttpModule是一個(gè)過(guò)濾器,那么我們可以在任何一個(gè)HttpModule
中終止當(dāng)前請(qǐng)求的執(zhí)行,執(zhí)行身份認(rèn)證,請(qǐng)問(wèn)文件的訪問(wèn)權(quán)限檢查等操作。我們可以自定義HttpModule擴(kuò)展,只是讓我們自己定義的類實(shí)現(xiàn)IHttpModule接口即可,
在IHttpModule 接口中有一個(gè)Init(HttpApplication app)方法,這是我們自定義擴(kuò)展Module的入口,我們可以在其中定義我們自己進(jìn)行的處理操作。
Init這個(gè)方法會(huì)接受一個(gè)HttpApplication類型的參數(shù),HttpApplication 在MSDN中的定義就是定義 ASP.NET 應(yīng)用程序中的所有應(yīng)用程序?qū)ο笸ㄓ玫姆椒?、屬性和?/P>
件。此類是用戶在 global.asax 文件中所定義的應(yīng)用程序的基類。HttpApplication 類的實(shí)例是在 ASP.NET 基礎(chǔ)結(jié)構(gòu)中創(chuàng)建的,而不是由用戶直接創(chuàng)建的。
HttpApplication 類的一個(gè)實(shí)例在其生存期內(nèi)被用于處理多個(gè)請(qǐng)求,但它一次只能處理一個(gè)請(qǐng)求。這樣,成員變量才可用于存儲(chǔ)針對(duì)每個(gè)請(qǐng)求的數(shù)據(jù)。
看到這個(gè)類的定義我們有沒(méi)有想到應(yīng)用程序池的概念,在IIS中我們新建一個(gè)應(yīng)用程序就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的應(yīng)用程序池,其實(shí)在應(yīng)用程序池中存儲(chǔ)的是什么?應(yīng)該就是
這些HttpApplication對(duì)象。每個(gè)請(qǐng)求會(huì)有一個(gè)對(duì)應(yīng)的HttpApplication對(duì)象來(lái)全程的負(fù)責(zé)它的執(zhí)行,在httpApplication對(duì)象中包含著請(qǐng)求所需要的所有參數(shù)值。例如
Response、Request、Cache等.Net常用的對(duì)象,甚至我們可以通過(guò)這個(gè)變量獲取到web.config中定義的所有Module擴(kuò)展。HttpApplication會(huì)伴隨著請(qǐng)求的全部
執(zhí)行過(guò)程。
現(xiàn)在一個(gè)問(wèn)題又來(lái)了,這個(gè)Module擴(kuò)展需要傳遞一個(gè)HttpApplication對(duì)象作為參數(shù),那么這個(gè)方法的參數(shù)是由誰(shuí)創(chuàng)建的呢?我們應(yīng)該經(jīng)常用到一個(gè)類
HttpRuntime,根據(jù)這個(gè)字面意思,我們也可以想到這個(gè)就是表示的Http運(yùn)行時(shí),是的,在IIS將請(qǐng)求的數(shù)據(jù)準(zhǔn)備好以后會(huì)通過(guò)HttpRuntime 調(diào)用
HttpApplicationFactory的一個(gè)Create()方法來(lái)得到一個(gè)HttpApplication對(duì)象,然后把參數(shù)值傳遞給這個(gè)對(duì)象,最后這個(gè)對(duì)象會(huì)傳遞到Module擴(kuò)展中。
現(xiàn)在請(qǐng)求經(jīng)過(guò)了Module擴(kuò)展過(guò)濾之后,就要進(jìn)入到真正處理它的地方了,HttpHandler,提起它,如果我們有點(diǎn)陌生,那么我們一定使用過(guò).Net中的一般處理程序,
我們可以看到一般處理程序是一個(gè)ashx文件,其中會(huì)繼承自IHttpHandler接口,進(jìn)行ProcessRequest處理。其實(shí)我們的HttpHandler就是ashx文件的codeBehind
文件。只要我們實(shí)現(xiàn)了IHttpHandler接口中的方法,就定義了一個(gè)Handler擴(kuò)展。
HttpHandler 是作為處理者的角色出現(xiàn)的,不是過(guò)濾者,所以Handler會(huì)有輸出結(jié)果。如果你要在Handler中使用Session,那么就要繼承IRequiredSessionState
接口,或者加上一個(gè)IReadOnlySessionState接口,這樣我們操作Session的時(shí)候才不會(huì)出現(xiàn)錯(cuò)誤。在Handler中我們可以進(jìn)行任何我們想要的操作,例如生成圖片
水印、防盜鏈甚至是文件的輸出壓縮以及編碼等都可以實(shí)現(xiàn)。
像我們的Web Service以及一般處理程序,從本質(zhì)上說(shuō)都是Handler的一種高層實(shí)現(xiàn)方式,都是進(jìn)行了Handler的擴(kuò)展操作。
因?yàn)槲覀冇懻摰氖荕VC,所以我們不得不考慮路由Route,其實(shí)Route是Mvc中的一個(gè)單獨(dú)的組件,它在我們的整個(gè)請(qǐng)求中也占據(jù)了非常重要的地位。在IIS通過(guò)IIS擴(kuò)
展選擇了適當(dāng)?shù)奶幚沓绦騺?lái)處理這個(gè)請(qǐng)求的時(shí)候,就是路由出現(xiàn)的時(shí)候,路由會(huì)根據(jù)路由配置分析這個(gè)路徑的ControllerName以及ActionName,對(duì)應(yīng)的參數(shù)值,然
后會(huì)把這些參數(shù)存儲(chǔ)到RouteData中,RouteTable.Routes 是一個(gè)路由集合,RouteData和HttpContext上下文就會(huì)組成另一個(gè)類的對(duì)象,RequestContext,我
們?cè)贛VC編程的時(shí)候,經(jīng)常會(huì)用到這個(gè)對(duì)象中的一些數(shù)據(jù)。.Net框架會(huì)根據(jù)RequestContext對(duì)象的值來(lái)匹配程序中的Controller以及Action,然后調(diào)用
ControllerDescriptor 執(zhí)行Controller,生成Controller的對(duì)象,然后通過(guò)ActionInvoke方法來(lái)執(zhí)行具體的Action。
在Action執(zhí)行完畢,返回對(duì)應(yīng)的視圖的時(shí)候,整個(gè)請(qǐng)求在.Net框架中的處理就算結(jié)束了。在輸出結(jié)果返回到用戶瀏覽器之前,輸出結(jié)果還會(huì)經(jīng)過(guò)Module擴(kuò)展的最后處
理,輸出結(jié)果到達(dá)IIS,最后IIS通過(guò)Http.sys響應(yīng)到用戶瀏覽器上,用戶就可以看到輸出結(jié)果。
因?yàn)橐粋€(gè)請(qǐng)求從進(jìn)入到顯示在瀏覽器上會(huì)兩次經(jīng)過(guò)Module擴(kuò)展,這就是為什么我們?cè)趙eb form中可以定義一個(gè)開(kāi)始事件,然后還會(huì)有一個(gè)完成事件的原因。
總結(jié)一下,一個(gè)用戶發(fā)起的請(qǐng)求通過(guò)http.sys-->IIS-->aspnet_iisapi.dll-->對(duì)應(yīng)的處理程序-->Module--->Handler-->Module--->IIS-->http.sys-->用戶瀏覽器。
當(dāng)然這個(gè)請(qǐng)求的順序不是特別的準(zhǔn)確,因?yàn)槭÷粤撕枚嗟募?xì)節(jié),但是從大的方面說(shuō)就是這些功能??赡苣銜?huì)有一個(gè)疑問(wèn),aspx文件沒(méi)有是什么時(shí)候執(zhí)行的呢?其實(shí)這
個(gè)問(wèn)題我以前也有想過(guò),aspx是在Module之后處理的,但是在handler之后還是之前呢?今天終于得到了答案,其實(shí)一個(gè)單獨(dú)的aspx文件就是一個(gè)handler,每個(gè)
aspx文件在編譯的時(shí)候都會(huì)編譯成一個(gè)類,這個(gè)類繼承自Page,但是Page繼承自哪里呢?
復(fù)制代碼 代碼如下:
public class Page : TemplateControl, IHttpHandler
我們可以看到Page繼承自IHttpHandler接口,這就驗(yàn)證了Page類的執(zhí)行是在Handler執(zhí)行的時(shí)候觸發(fā)的。
一個(gè)小小的http請(qǐng)求會(huì)讓我們有那么多的知識(shí)要掌握,我們作為程序員對(duì)于這個(gè)請(qǐng)求的模型應(yīng)該是很熟悉。但是作為.Net 拖控件開(kāi)發(fā)的程序員,我善意的提醒一下,
如果可以不用控件,我們就別用了,用js、css來(lái)代替吧,畢竟html是基礎(chǔ)。在Mvc時(shí)代到來(lái)的時(shí)候,,擁抱新技術(shù)吧。
我是小兵,沒(méi)有太多的發(fā)言權(quán),所以我就是按小兵的思路來(lái)分析大牛們的技術(shù)。

您可能感興趣的文章:- Asp.net實(shí)現(xiàn)MVC處理文件的上傳下載功能實(shí)例教程
- ASP.NET mvc異常處理的方法示例介紹
- ASP.NET 回發(fā)密碼框清空問(wèn)題處理方法
- asp.net錯(cuò)誤頁(yè)面處理示例分享
- ASP.NET MVC處理文件上傳的小例子
- ASP.NET中在一般處理程序中使用session的簡(jiǎn)單介紹
- asp.net上傳圖片并作處理水印與縮略圖的實(shí)例代碼
- asp.net4.0框架下驗(yàn)證機(jī)制失效的原因及處理辦法
- Asp.net請(qǐng)求處理之管道處理介紹
- asp.net通過(guò)HttpModule自動(dòng)在Url地址上添加參數(shù)
- 攔截asp.net輸出流并進(jìn)行處理的方法