ASP.NET Core管道深度剖析(1):採用管道處理HTTP請求

發表於2016-05-30

之所以稱ASP.NET Core是一個Web開發平臺,源於它具有一個極具擴充套件性的請求處理管道,我們可以通過這個管道的定製來滿足各種場景下的HTTP處理需求。ASP. NET Core應用的很多特性,比如路由、認證、會話、快取等,也同時定製訊息處理管道來實現的。我們甚至可以通過管道定製在ASP.NET Core平臺上建立我們自己的Web框架,實際上MVC和SingalR這兩個重要的Web框架也是採用這樣的方式建立的。

HTTP協議自身的特性決定了任何一個Web應用的工作方式都是監聽、接收並處理HTTP請求,並在最終對請求予以響應,HTTP請求處理是管道式設計典型的應用場景。我們根據HTTP請求的處理流程定製出一個訊息處理管道,讓接收到的HTTP請求訊息想水一樣流入這個管道,組成這個管道的各個環節一次對它作相應的處理。

處理的結果同樣轉變成訊息逆向流入這個管道進行處理,並最終轉變成回覆給客戶端的HTTP響應。ASP.NET Core的訊息處理管道從設計的角度來講是非常簡單的,但是從具體實現的角度則相對難以理解,為了讓讀者朋友們通過本章對此具有深刻的理解,我們從簡單的部分講起。

一、從Hello World說起

為了使讀者朋友們能夠以最直觀的感受認識ASP.NET Core的訊息處理管道,我們來建立一個最簡單的Hello World程式。這是一個僅僅由兩個型別構成的控制檯程式,作為程式入口的Main方法定義在Program類中,Startup則作為初始化型別。這個程式被啟動之後將會繫結到預設埠5000進行HTTP請求的監聽,任何針對基地址 “http://localhost:5000/” 的請求後,該程式都將響應 “Hello World” 。

這個程式涉及到一個重要的物件WebHost,它通過WebHostBuilder的Build方法建立。WebHost可以看成是Web應用的宿主,啟動Web應用本質上就是啟動它的宿主。當我們呼叫WebHost的Start方法啟動應用的時候,用於監聽、接收、處理和響應HTTP請求的訊息處理管道隨之被建立。

那麼在這個過程中,通過呼叫UseStartup方法註冊到WebHostBuilder上的初始化型別將用來對這個管道進行定製。總的來說,ASP.NET Core的請求處理管道由WebHost在啟動的時候構建,WebHostBuilder則是後者的建立者,右圖揭示了三者之間的關係。

clip_image002

二、管道的構成

HTTP請求處理流程始於對請求的監聽與接收,終於對請求的響應,這兩項工作由同一個物件來完成,我們稱之為 “伺服器(Server)” ,儘管ASP.NET Core的請求處理管道可以被自由地訂製,但是該管道必須有一個伺服器,伺服器是整個管道的 “龍頭” 。

在上面的這個Hello World應用中,在呼叫WebHostBuilder的Build方法建立一個WebHost之前,我們呼叫了它的一個擴充套件方法UseKestrel,這個方法的作用就是為後續構建的管道註冊一個名為KestrelServer的伺服器。

7-2

隨著WebHost的Start方法的呼叫,按照具體需求進行定製的請求處理管道被構建出來,作為第一個節點的伺服器會繫結到一個預設的埠(比如KestrelServer預設採用5000作為監聽埠)開始監聽來自客戶端的HTTP請求。一旦請求抵達,伺服器會接收請求並將其標準化後向管道後續的節點進行轉發,我們將管道中位於伺服器之後的請求處理節點成為“中介軟體(Middleware)”。

每個中介軟體都具有各自獨立的功能,比如我們有專門實現路由功能的中介軟體,由專門實施使用者認證的中間,所謂的對請求處理管道的定製體現在根據具體的需求選擇對應的中介軟體組成最終處理請求的管道。左圖揭示了由一個伺服器和一組中介軟體構成的請求處理管道。

clip_image006

一個建立在ASP.NET Core之上的應用一般都是根據某個框架開發的,開發框架基本上是建立在某個特殊的中介軟體上。以ASP.NET Core MVC這個最著名的框架為例,它實際上是利用一個叫做 “路由” 的中介軟體實現了請求地址與Controller/Action之間的對映,並在此基礎實現了啟用Controller、執行Action以及呈現View等一系列的功能。所以應用程式可以視為某個中介軟體的一部分,如果一定要將它獨立出來,整個請求處理管道將呈現出如右圖所示的結構。

三、管道的定製

在演示的Hello World程式中,我們在呼叫WebHostBuilder的Build方法建立WebHost之前先呼叫了它的擴充套件方法UseStartup方法註冊了一個型別為Startup的啟動型別。從請求處理管道的角度來講,註冊的這個啟動型別的目的在於對構建的管道進行定製,說得更加具體一點,我們利用這個型別為管道註冊需要的中介軟體。

一般來說,被註冊的啟動型別必須具有一個類似於下面程式碼片斷所示的Configure方法,這個方法可以是靜態方法和也可以例項方法。這個方法的引數並沒有嚴格的限制,但是第一個引數型別必須是IApplicationBuilder介面。

對中介軟體的註冊就是實現在這樣一個Configure方法之中。在演示的例項中,我們呼叫了IApplicationBuilder介面的擴充套件方法Run註冊了一箇中介軟體,它承載的請求處理邏輯很簡單,即使直接響應一個“Hello World”字串。在真實的專案中,我們會根據具體的應用場景在這樣一個方法中利用ApplicationBuilder註冊相應的中介軟體進而構建一個適合當前請求處理需求的管道。

比如在一個ASP.NET Core MVC應用中我們除了按照如上的方式呼叫擴充套件方法UseMvc註冊了支撐MVC框架的中介軟體(實際上是一個實現路由的中介軟體)之外,我們還通過呼叫其它的擴充套件方法註冊了相應的中介軟體實現了對靜態檔案的訪問(UseStaticFiles)、錯誤頁面的呈現(UseExceptionHandler)以及基於ASP.NET Identity Framework的認證(UseIdentity)。

相關文章