ASP.Net请求小周期
ASP.NET請求處理全過程
一個ASP.NET請求過程中,從瀏覽器中發(fā)出一個Web請求 到 這個請求被響應(yīng)并顯示在瀏覽器中的過程中究竟會發(fā)生哪些不同的事件,當(dāng)我們進(jìn)入這個事件之旅時,我們也會試著明白在請求處理的每個事件當(dāng)中我們可以做什么業(yè)務(wù)邏輯處理操作。
首先把整個過程大致分成兩步:
- ASP.NET會創(chuàng)建一個能夠處理請求的環(huán)境。換句話說,它會創(chuàng)建一個包含請求、響應(yīng)以及上下文對象的應(yīng)用程序?qū)ο髞硖幚磉@個請求。
- 一旦ASP.NET環(huán)境被創(chuàng)建,用戶請求就會通過由modules(管道)、handlers(處理程序)和page objects(頁面對象)觸發(fā)的一系列事件進(jìn)行處理。簡而言之,我們暫且將此步稱為MHPM(Module、Handler、Page和Module Event)。
ASP.NET環(huán)境的創(chuàng)建
- 第一步:用戶請求到達(dá)IIS后,發(fā)現(xiàn)處理不了這個后綴的文件,就去查找映射表。IIS首先會檢查哪一個ISAPI擴(kuò)展能夠處理這個請求,這會取決于文件的后綴名。例如:如果請求的是一個'.aspx'的頁面,那么就會被傳遞到'aspnet_isapi.dll'來進(jìn)行處理。
- 第二步:如果這是該網(wǎng)站的首次請求,那么一個稱為'ApplicationManager'的類會首先創(chuàng)建一個該網(wǎng)站可以運行的應(yīng)用程序域(App Domain)。正如我們所知,應(yīng)用程序域隔離部署在同一臺IIS服務(wù)器上的兩個不同的Web應(yīng)用程序。因此,即使其中一個應(yīng)用程序域出現(xiàn)了錯誤,也不會影響其他應(yīng)用程序域的正常運作。
應(yīng)用程序域
.NET平臺下,程序集并沒有直接加載進(jìn) 進(jìn)程 中(傳統(tǒng)的Win32程序是直接承載的)。.NET可執(zhí)行程序承載在進(jìn)程的一個邏輯分區(qū)中,術(shù)語稱應(yīng)用程序域(簡稱AppDomain)。應(yīng)用程序域是.NET引入的一個新概念,它比進(jìn)程所占用的資源要少,可以被看作是一個 輕量級的進(jìn)程。
- 第三步:在新創(chuàng)建的應(yīng)用程序域中,會創(chuàng)建ASP.NET的宿主環(huán)境,也就是HttpRuntime對象。一旦宿主環(huán)境被創(chuàng)建完成,網(wǎng)站調(diào)用HttpRuntime類的靜態(tài)方法處理請求,ASP.NET最核心的對象如HttpContext、HttpRequest和HttpResponse對象都會被創(chuàng)建好。HttpApplication對象將會被分配給一系列的ASP.NET核心對象來處理請求的頁面。
這里面主要包括:
- 分析請求報文,并將報文數(shù)據(jù)封裝到一個叫HttpWorkRequest類對象應(yīng)用的屬性中
- 通過調(diào)用HttpApplicationFactory類的一個靜態(tài)方法創(chuàng)建HttpApplication對象(這里每次HttpApplicationFactory都會到HttpApplication池中去查找,看看有沒用空閑的HttpApplication對象,如果有,就直接拿來使用,否則才創(chuàng)建新的使用,網(wǎng)站針對此次請求的所有運行過程都在這個對象中完成)
如果你的系統(tǒng)中存在一個global.asax文件,那么這個global.asax文件的對象也會被創(chuàng)建。但是,需要注意的是你的global.asax需要繼承自HttpApplication類。
global.asax
Global.asax 文件(也稱作 ASP.NET 應(yīng)用程序文件)是可選文件,包含用于響應(yīng) ASP.NET 或 HttpModule 引發(fā)的應(yīng)用程序級別事件的代碼。(換句話說,我們可以自定義后面我們所要介紹的一些事件,因為請求處理流程會經(jīng)歷后面的10多個事件,我們可以寫代碼來自定義其中的一些事件,加一些我們想做的業(yè)務(wù)邏輯操作,比如:URL重寫、身份驗證、圖片水印等等。)
-
創(chuàng)建HttpContext對象,這個對象是當(dāng)前請求的上下文環(huán)境,里面包含處理請求的所有參數(shù)數(shù)據(jù),其中最重要的就是HttpRequest和HttpResponse對象。
HttpRequest
對象主要包含了所有的請求信息,這些信息來源于HttpWorkRequest對象中包含的屬性:Form(客戶端表單數(shù)據(jù))、QueryString(客戶端url參數(shù))
HttpResponse
主要包含了TestWriter對象,用來保存頁面類型執(zhí)行過程中要輸入給瀏覽器的數(shù)據(jù)
- 因為HttpApplication里面運行IHttpHandler handler=(通過反射方式創(chuàng)建的被請求頁面類對象) 被請求頁面對象里的ProcessRequest方法,所以,需要將HttpContext對象傳入到HttpApplication中來,即HttpApplication對象將會被分配給一系列的ASP.NET核心對象來處理請求的頁面
- 第四步:這時,HttpApplication開始通過HTTP管道事件、處理程序(Handlers)和頁面事件來處理請求了。也就是說:它會觸發(fā) MHPM 中的事件來處理請求。
下圖則形象地展示了在一個ASP.NET請求過程中的重要內(nèi)部對象模型。最高層是ASP.NET運行時,它創(chuàng)建了一個應(yīng)用程序域(AppDoamin),下層則創(chuàng)建了一個包含request、response以及context對象的HttpRuntime。
.NET平臺處理HTTP請求的過程大致如下:
- 1、IIS得到一個請求;
- 2、查詢腳本映射擴(kuò)展,然后把請求映射到aspnet_isapi.dll文件
- 3、代碼進(jìn)入工作者進(jìn)程(IIS5里是aspnet_wp.exe;IIS6里是w3wp.exe),工作者進(jìn)程也叫輔助進(jìn)程;
- 4、.NET運行時被加載;
- 5、非托管代碼調(diào)用IsapiRuntime.ProcessRequest()方法;
- 6、每一個請求調(diào)用一個IsapiWorkerRequest;
- 7、使用WorkerRequest調(diào)用HttpRuntime.ProcessRequest()方法;
- 8、通過傳遞進(jìn)來的WorkerRequest創(chuàng)建一個HttpContext對象
- 9、通過把上下文對象作為參數(shù)傳遞給HttpApplication.GetApplicationInstance(),然后調(diào)用該方法,從應(yīng)用程序池中獲取一個HttpApplication實例;
- 10、調(diào)用HttpApplication.Init(),啟動管道事件序列,鉤住模塊和處理器;
- 11、調(diào)用HttpApplicaton.ProcessRequest,開始處理請求;
- 12、觸發(fā)管道事件;
- 13、調(diào)用HTTP處理器和ProcessRequest方法;
- 14、把返回的數(shù)據(jù)輸出到管道,觸發(fā)處理請求后的事件。
- 當(dāng)客戶端向Web服務(wù)器請求一個頁面文件時,這個HTTP請求會被inetinfo.exe進(jìn)程截獲(WWW服務(wù)),它判斷文件后綴,如果是*.aspx、*.asmx等,就把這個請求轉(zhuǎn)交給aspnet_isapi.dll,而aspnet_isapi.dll則會通過一個Http PipeLine的管道,將這個HTTP請求發(fā)送給w3wq.exe進(jìn)程,當(dāng)這個HTTP請求進(jìn)入w3wq.exe進(jìn)程之后,Asp.Net framework就會通過HttpRuntime來處理這個HTTP請求,處理完畢后將結(jié)果返回給客戶端。當(dāng)一個HTTP請求被送入到HttpRuntime之后,這個HTTP請求通過HTTP管道(HttpRuntime是HTTP管道的入口)被送入到一個被稱之為HttpApplication Factory的一個容器當(dāng)中,而這個容器會給出一個HttpApplication實例來處理傳遞進(jìn)來的HTTP請求,同時HttpApplication實例會創(chuàng)建一個HttpContext對象來記錄HTTP請求的上下文,而后這個HTTP請求會依次進(jìn)入到如下幾個容器中:HttpModule --> HttpHandler Factory --> HttpHandler.當(dāng)系統(tǒng)內(nèi)部的HttpHandler的ProcessRequest方法處理完畢之后,整個Http Request就被處理完成了.如果想在中途截獲一個HttpRequest并做些自己的處理,就應(yīng)該在HttpRuntime運行時內(nèi)部來做到這一點,確切的說時在HttpModule這個容器中做到這個的。
通過MHPM觸發(fā)的事件處理請求
一旦HttpApplication創(chuàng)建好,它就開始處理請求了。它經(jīng)歷了三個不同的部分:HttpModule、Page和HttpHandler。當(dāng)它經(jīng)過這些部分時,它將調(diào)用不同的事件,而這些事件的邏輯處理還可以由開發(fā)者來進(jìn)行擴(kuò)展和增加自定義處理。
先來了解一下什么是HttpModule和HttpHandlers。他們幫助我們在ASP.NET頁面處理過程的前后注入自定義的邏輯處理
他們之間主要的差別
如果你想要注入的邏輯是基于像'.aspx','.html'這樣的擴(kuò)展名,那么你可以使用HttpHandler。換句話說,HttpHandler是一個基于處理器的擴(kuò)展。
如果你想要在ASP.NET管道事件中注入邏輯,那么你可以使用HttpModule。也可以說,HttpModule是一個基于處理器的事件。
下面是請求處理過程的邏輯流程,其中有4個重要的步驟
- 第一步(M:HttpModule):客戶端請求開始被處理。在ASP.NET引擎執(zhí)行和創(chuàng)建HttpModule觸發(fā)事件(在此過程中,你也可以注入自定義邏輯)之前,有6個事件你可以在頁面對象創(chuàng)建之前來使用,它們分別是:BeginRequest、AuthenticateRequest、AuthorizeRequest、ResolveRequestCache、AcquireRequestState 以及 PreRequestHandlerExecute。
- 第二步(H:HttpHandler):一旦以上6個事件被觸發(fā)后,ASP.NET引擎就將會調(diào)用 ProcessRequest 事件,即使你已經(jīng)在項目中實現(xiàn)了HttpHandler。
- 第三步(P:ASP.NET Page):一旦HttpHandler邏輯執(zhí)行,ASP.NET頁面對象就被創(chuàng)建了。而ASP.NET頁面被創(chuàng)建,一系列的事件也會隨之被觸發(fā),它們可以幫助我們自定義邏輯注入到這些事件里邊。在此過程中,有6個重要事件給我們提供了占位符,以便我們在ASP.NET頁面中寫入邏輯,它們分別是:Init、Load、Validate、Render 和 Unload。你可以通過記住單詞SILVER來記憶這幾個事件,S—Start(沒有任何意義,僅僅是為了形成一個單詞),I(Init)、L(Load)、V(Validate)、E(Event)、R(Render)。
- 第四步(M:HttpModule):一旦頁面對象執(zhí)行結(jié)束并從內(nèi)存中被卸載,HttpModule提供了提交返回頁面的執(zhí)行事件,同樣,在這些事件中也可以被注入自定義的返回處理邏輯。這里有4個重要的提交處理事件:PostRequestHandlerExecute、ReleaserequestState、UpdateRequestCache以及EndRequest
下圖形象地展示了上面的四個步驟:
對于執(zhí)行HttpApplication的ProcessRequest方法這個過程可以看成一個管道,要先后按照順序執(zhí)行19個委托事件,其中第八個時,創(chuàng)建 被請求的頁面對象,第11到12事件之間,執(zhí)行了被創(chuàng)建的頁面類對象的ProcessRequest方法
什么是請求管道?
請求管道就是把Application的一系列事件串聯(lián)成一條線,這些事件按照排列的先后順序依次執(zhí)行,事件處理的對象包括HttpModule、HttpHandler、ASP.NET Page
熟悉請求管道實現(xiàn)程序運行的全過程:
- BeginRequest:開始處理請求
- AuthenticateRequest:授權(quán)驗證請求,獲取用戶授權(quán)信息
- PostAuthenticateRequest:獲取成功
- AunthorizeRequest:授權(quán),一般來檢查用戶是否獲得權(quán)限
- PostAuthorizeRequest:獲得授權(quán)
- ResolveRequestCache:獲取頁面緩存結(jié)果
- PostResolveRequestCache:已獲取緩存
- PostMapRequestHandler:創(chuàng)建頁面對象
- AcquireRequestState:獲取Session-----先判斷當(dāng)前頁面對象是否實現(xiàn)了IRequiresSessionState接口,如果實現(xiàn)了,則從瀏覽器發(fā)來的請求報文體中獲得SessionID,并到服務(wù)器的Session池中獲得對應(yīng)的Session對象,最后賦值給HttpContext的Session屬性
- PostAcquireRequestState:獲得Session
- PreRequestHandlerExecute:準(zhǔn)備執(zhí)行頁面對象,執(zhí)行頁面對象的ProcessRequest方法
- PostRequestHandlerExecute:執(zhí)行完頁面對象了
- ReleaseRequestState:釋放請求狀態(tài)
- PostReleaseRequestState:已釋放請求狀態(tài)
- UpdateRequestCache:更新緩存
- PostUpdateRequestCache:已更新緩存
- LogRequest:日志記錄
- PostLogRequest:已完成日志
- EndRequest完成
詳解ASP.NET頁面事件
在上面的部分中,我們已經(jīng)了解了一個ASP.NET頁面請求事件的整體流程。那么,在其中一個最重要的部分就是ASP.NET頁面,但是我們并沒有對其進(jìn)行詳細(xì)討論
每一個ASP.NET頁都有2個部分:一個是在瀏覽器中進(jìn)行顯示的部分,它包含了HTML標(biāo)簽、viewstate形式的隱藏域 以及 在HTML input中的數(shù)據(jù)。當(dāng)這個頁面被提交到服務(wù)器時,這些HTML標(biāo)簽會被創(chuàng)建到ASP.NET控件,并且viewstate還會和表單數(shù)據(jù)綁定在一起。一旦你在后置代碼中得到所有的服務(wù)器控件,你可以執(zhí)行和寫入你自己的邏輯并呈現(xiàn)給客戶瀏覽器。
當(dāng)頁面進(jìn)行回發(fā)時,如點擊按鈕,以上事件都會重新執(zhí)行一次,這時的執(zhí)行順序為:
- OnPreInit
- OnInit
- OnInitComplete
- OnPreLoad
- Page_Load
- OnLoad
- Button_Click
- OnLoadComplete
- OnPreRender
轉(zhuǎn)載于:https://www.cnblogs.com/wwkk/p/6606623.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的ASP.Net请求小周期的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringMVC:学习笔记(10)——
- 下一篇: 深入.NET框架