mvc請求管道(一)
- 2019 年 10 月 22 日
- 筆記
一、前言
在平常做後台開發的時候,經常會說到請求管道,很多開發者都知道這個,也能說幾句,可能沒法詳細的去介紹,今天就來詳細的說一下這個。
二、到達IIS之前
請看下面這個流程圖。從用戶打開瀏覽器到請求到達伺服器,這些都是需要我們去配置就行了,這裡面有一些知識點,http/https、tcp/ip、dns解析這些感興趣的可以去了解一下。
三、請求到達IIS
同樣先看流程圖,Sys服務監聽到有請求到達IIS,IIS會把這個請求轉發給ISAPI,ISAPI即Internet Server Application Program Interface (互聯網應用服務介面),是微軟提供的一套面向Internet服務的API介面,它根據後綴判斷需要把該請求轉發給誰處理,.net的請求會轉發到asp.net_ISAPI,它屬於IIS,運行在IIS進程中的,它會用Pipeline的方式把請求轉交給.Net Framework,它很像一個隊列(先進先出),可以對請求進行排隊處理,在請求處理完,會釋放掉該請求佔用的socket鏈接。
四、請求到達應用程式
慣例,先上圖。HTTPRuntime.ProcessRequest是整個應用程式的入口,這一步會接收上一步打包的HTTPWorkerRequest,完成HttpContext的初始化,調用HttpApplicaFactory工廠類創建HttpApplication(HttpApplication實現了IHttpHandler),HttpApplicationFactory.GetApplicationInstance創建HttpApplication實例中有三個關鍵方法:
1. HttpApplicationFactory._theApplicationFactory.EnsureInited()該方法檢查HttpApplicationFactory是否被初始化(它是存放在一個棧裡面的)如果沒有,就通過HttpApplicationFactory.Init()進行初始化。在Init()中,先獲取Global.asax文件的完整路徑,然後調用CompileApplication()對Global.asax進行編譯。
2. HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context) 創建特定的HttpApplication實例,觸發ApplicationOnStart事件,執行ASP.Global.asax中的Application_Start(object sender, EventArgs e)方法。這裡創建的HttpApplication實例在處理完事件後,就被回收。
3. HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context) 該方法創建HttpApplication實例並進行初始化,調用System.Web.HttpApplication.InitInternal()方法。創建HttpApplication實例是根據實際的_theApplicationType進行創建。如果Web目錄中沒有global.asa文件,也就是說沒有動態編譯生成ASP.Global.asax類型,那就直接實例化HttpApplication。如果創建了ASP.Global.asax類型,那就對ASP.Global.asax進行實例化。
五、請求到達MVC的處理管線
上面大概介紹了Asp.Net Mvc的請求到達應用程式的管道,接下來就是和我們編碼息息相關的處理流程了,下面這張圖是我在以前查閱資料的時候保存下來了,出處已經找不到,如果有知道可以留個言。
當請求到達應用程式之後,第一站就是路由模組,MVC會根據RouteTable(一般都在RouteConfig中配置,在MVC第一次啟動時,路由系統就會把我們註冊的路由規則,寫在Glocal.asax中的Application_Start事件中)中配置的路由模板去匹配當前的請求,獲取對應的Controller和Action資訊,具體的匹配過程是由UrlRoutingModule(System.Web.Routing.UrlRoutingModule)來實現的。
當UrlRoutingModule在Route Table中找到一條匹配的路由規則時,就會為這條路由規則尋找對應的IRouteHandler(System.Web.Mvc.IRouteHandler)實例(默認是System.Web.MvcRouteHandler),根據這個RouteHandler最後獲取一個IHttpHandler的實例(默認是System.Web.MvcHandler)。在處理完路由資訊和匹配到之後,就來到了Controller。
在MvcHandler中的ProcessRequest方法中就是ASP.NET MVC的生命周期,這個方法使用IControllerFactory的實例(默認是System.Web.Mvc.DefaultControllerFactory)來創建相應的Controller。
創建完Controller之後,就會執行Controller的invokeAction()方法,找到合適的Action後,就是Model Binding(默認是System.Web.Mvc.DefaultModelBinder),它會從Http請求的參數中提取數據並實現類型轉換,數據校驗(例如是否必填,數據格式等)以及是否自動裝配到Action方法的參數中。
完成模型綁定之後就是執行Filter了,Filter也是一個可以鋪開說的知識,這裡先只簡單的介紹一下,從下圖看到第一個是Authentication Filter,它是MVC5中新增的一個Filter,它會先於Authorization Filter執行,目的是對訪問用戶的認證。在MVC5之前,認證和授權都是通過Authorization Filter來實現的。然後是Authorization Filter 這個主要是驗證授權的,授權驗證通過後執行的Action Filter,自定義Action Filter需繼承ActionFilterAttribute,它分為兩個方法,OnActionExecuting和OnActionExecuted分別在action執行前後執行,我們可以通過實現IActionFilter介面來實現你個性化的過濾機制。在Action Filter執行之後,就會執行我們的業務程式碼了。
在執行完業務程式碼,會執行ActionResult,ActionResult也有一個Filter,自定義ActionResult Filter需繼承ActionFilterAttribute它也分為兩個方法:OnResultExecuting和OnResultExecuted,它是在動作結果被執行之前和之後運行。ActionResult就是把後台處理的用戶請求結果返回。因此ViewResult、PartialViewResult、RedirectToRouteResult、RedirectResult、ContentResult、JsonResult、FileResult 和 EmptyResult就是具體的返回類型。
最後還有一個Exception Filter,它只有在當Action執行發生未處理異常的時候執行OnException方法。自定義Exception Filter需要繼承HandleErrorAttribute類,重寫OnException方法。
在ActionResult執行完成之後,就是View的初始化和渲染了,ViewResult最終是由View Engine通過調用IView的Render()方法來呈現View的,整個處理過程是由IViewEngine(System.Web.Mvc.IViewEngine)來實現的。ASP.Net MVC 默認提供WebForm(.aspx)和Razor(.cshtml)模板引擎,你也可以通過實現IViewEngine介面來實現你自己的ViewEngine,然後在Application_Start方法中做如下操作:
protected void Application_Start() { //移除所有的View引擎包括Webform和Razor ViewEngines.Engines.Clear(); //註冊你自己的View引擎 ViewEngines.Engines.Add(new CustomViewEngine()); }
在頁面里,我們可以直接寫html標籤,也可以用@Html等來實現。@Html是使用Html Helpers來生成我們需要的html標籤,當然它也支援自定義和擴展,這樣就可以解決我們一些訂製化的需求。
六、總結
在上面所有的操作都完成之後,IIS會把結果返回給用戶,用戶才能看到他需要的結果。在整個請求管道中,一般分為19個事件,如下,
事件名稱: |
簡單描述: |
BeginRequest |
在 ASP.NET 響應請求時作為 HTTP 執行管線鏈中的第一個事件發生 |
AuthenticateRequest |
當安全模組已建立用戶標識時發生。註:AuthenticateRequest 事件發出訊號表示配置的身份驗證機制已對當前請求進行了身份驗證。預訂 AuthenticateRequest 事件可確保在處理附加的模組或事件處理程式之前對請求進行身份驗證
|
PostAuthenticateRequest |
當安全模組已建立用戶標識時發生。PostAuthenticateRequest 事件在 AuthenticateRequest 事件發生之後引發。預訂 PostAuthenticateRequest 事件的功能可以訪問由 PostAuthenticateRequest 處理的任何數據 |
AuthorizeRequest |
當安全模組已驗證用戶授權時發生。AuthorizeRequest 事件發出訊號表示 ASP.NET 已對當前請求進行了授權。預訂 AuthorizeRequest 事件可確保在處理附加的模組或事件處理程式之前對請求進行身份驗證和授權 |
PostAuthorizeRequest |
在當前請求的用戶已獲授權時發生。PostAuthorizeRequest 事件發出訊號表示 ASP.NET 已對當前請求進行了授權。預訂PostAuthorizeRequest 事件可確保在處理附加的模組或處理程式之前對請求進行身份驗證和授權 |
ResolveRequestCache |
當 ASP.NET 完成授權事件以使快取模組從快取中為請求提供服務時發生,從而跳過事件處理程式(例如某個頁或 XML Web services)的執行 |
PostResolveRequestCache |
在 ASP.NET 跳過當前事件處理程式的執行並允許快取模組滿足來自快取的請求時發生。)在 PostResolveRequestCache 事件之後、PostMapRequestHandler 事件之前創建一個事件處理程式(對應於請求 URL 的頁 |
PostMapRequestHandler |
在 ASP.NET 已將當前請求映射到相應的事件處理程式時發生。
|
AcquireRequestState |
當 ASP.NET 獲取與當前請求關聯的當前狀態(如會話狀態)時發生。
|
PostAcquireRequestState |
在已獲得與當前請求關聯的請求狀態(例如會話狀態)時發生。
|
PreRequestHandlerExecute |
恰好在 ASP.NET 開始執行事件處理程式(例如,某頁或某個 XML Web services)前發生。
|
PostRequestHandlerExecute |
在 ASP.NET 事件處理程式(例如,某頁或某個 XML Web service)執行完畢時發生。
|
ReleaseRequestState
|
在 ASP.NET 執行完所有請求事件處理程式後發生。該事件將使狀態模組保存當前狀態數據。
|
PostReleaseRequestState
|
在 ASP.NET 已完成所有請求事件處理程式的執行並且請求狀態數據已存儲時發生。
|
UpdateRequestCache
|
當 ASP.NET 執行完事件處理程式以使快取模組存儲將用於從快取為後續請求提供服務的響應時發生。
|
PostUpdateRequestCache
|
在 ASP.NET 完成快取模組的更新並存儲了用於從快取中為後續請求提供服務的響應後,發生此事件。
|
LogRequest
|
在 ASP.NET 完成快取模組的更新並存儲了用於從快取中為後續請求提供服務的響應後,發生此事件。 僅在 IIS 7.0 處於集成模式並且 .NET Framework 至少為 3.0 版本的情況下才支援此事件
|
PostLogRequest
|
在 ASP.NET 處理完 LogRequest 事件的所有事件處理程式後發生。 僅在 IIS 7.0 處於集成模式並且 .NET Framework 至少為 3.0 版本的情況下才支援此事件。
|
EndRequest
|
在 ASP.NET 響應請求時作為 HTTP 執行管線鏈中的最後一個事件發生。 在調用 CompleteRequest 方法時始終引發 EndRequest 事件。
|
寫的可能不是十分詳細,基本也差不多了,如果有什麼不對的地方歡迎指正。