通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流程[上]:采用管道处理请求...
之所以稱ASP.NET Core是一個(gè)Web開(kāi)發(fā)平臺(tái),而不是一個(gè)單純的開(kāi)發(fā)框架,源于它具有一個(gè)極具擴(kuò)展性的請(qǐng)求處理管道,我們可以通過(guò)對(duì)這個(gè)管道的定制來(lái)滿足各種場(chǎng)景下的HTTP處理需求。ASP. NET Core應(yīng)用的很多特性,比如路由、認(rèn)證、會(huì)話、緩存等,都是通過(guò)對(duì)管道的定制來(lái)實(shí)現(xiàn)的。我們甚至可以通過(guò)管道定制在ASP.NET Core平臺(tái)上創(chuàng)建我們自己的Web框架,實(shí)際上MVC和SingalR這兩個(gè)重要的Web框架也是采用這樣的方式創(chuàng)建的。 [本文已經(jīng)同步到《ASP.NET Core框架揭秘》之中] [源代碼從這里下載]
目錄
一、從Hello World說(shuō)起
二、管道的構(gòu)成
三、管道的定制
一、從Hello World說(shuō)起
HTTP協(xié)議自身的特性決定了任何一個(gè)Web應(yīng)用的工作方式都是監(jiān)聽(tīng)、接收并處理HTTP請(qǐng)求,并在最終對(duì)請(qǐng)求予以響應(yīng),HTTP請(qǐng)求處理是管道式設(shè)計(jì)典型的應(yīng)用場(chǎng)景。具體來(lái)說(shuō),我們根據(jù)具體的HTTP處理請(qǐng)求構(gòu)建一個(gè)管道,接收到的HTTP請(qǐng)求消息想水一樣流入這個(gè)管道,組成這個(gè)管道的各個(gè)環(huán)節(jié)依次對(duì)它作相應(yīng)的處理。處理的結(jié)果同樣轉(zhuǎn)變成消息逆向流入這個(gè)管道進(jìn)行處理,并最終轉(zhuǎn)變成回復(fù)給客戶端的HTTP響應(yīng)。ASP.NET Core的消息處理管道從設(shè)計(jì)的角度來(lái)講是非常簡(jiǎn)單的,但是從具體實(shí)現(xiàn)的角度則相對(duì)復(fù)雜并相對(duì)難以理解,為了讓讀者朋友們通過(guò)本章對(duì)此具有深刻的理解,我們從簡(jiǎn)單的部分講起。
為了使讀者朋友們能夠以最直觀的感受認(rèn)識(shí)ASP.NET Core的消息處理管道,我們來(lái)創(chuàng)建一個(gè)最簡(jiǎn)單的Hello World程序。這是一個(gè)控制臺(tái)應(yīng)用,整個(gè)程序由如下所示的五行代碼組成。當(dāng)我們運(yùn)行這個(gè)程序之后,一個(gè)名為KestrelServer的服務(wù)器將會(huì)啟動(dòng)并綁定到本機(jī)上的5000端口進(jìn)行請(qǐng)求監(jiān)聽(tīng)。針對(duì)所有接收到的請(qǐng)求,我們都有會(huì)響應(yīng)一個(gè)“Hello World”字符串。
1: public?class Program 2: { 3:???? public?static?void Main() 4:???? { 5:???????? new WebHostBuilder() 6:???????????? .UseKestrel() 7:???????????? .Configure(app => app.Run(async context=> await context.Response.WriteAsync("Hello World")))??????????? 8:???????????? .Build() 9:???????????? .Run(); 10:???? } 11: }這個(gè)程序涉及到一個(gè)名為WebHost重要的對(duì)象, 它可以看成是Web應(yīng)用的宿主,啟動(dòng)Web應(yīng)用本質(zhì)上就是啟動(dòng)作為宿主的WebHost對(duì)象。WebHostBuilder是WebHost的創(chuàng)建者,我們調(diào)用它的Build方法創(chuàng)建相應(yīng)的WebHost。當(dāng)我們調(diào)用WebHost的擴(kuò)展方法Run啟動(dòng)應(yīng)用的時(shí)候,用于監(jiān)聽(tīng)、接收、處理和響應(yīng)HTTP請(qǐng)求的管道隨之被建立。那么在這個(gè)過(guò)程中,通過(guò)調(diào)用Configure方法注冊(cè)到WebHostBuilder上的委托對(duì)象(委托類型為Action<IApplicationBuilder>)將用于管道的定制。總的來(lái)說(shuō),ASP.NET Core管道由WebHost在啟動(dòng)的時(shí)候構(gòu)建,WebHostBuilder則是后者的創(chuàng)建者,下圖揭示了三者之間的關(guān)系。
?
二、管道的構(gòu)成
HTTP請(qǐng)求處理流程始于對(duì)請(qǐng)求的監(jiān)聽(tīng)與接收,終于對(duì)請(qǐng)求的響應(yīng),這兩項(xiàng)工作均由同一個(gè)對(duì)象來(lái)完成,我們稱之為 “服務(wù)器(Server)” 。盡管ASP.NET Core的請(qǐng)求處理管道可以被自由地訂制,但是該管道必須有一個(gè)Server,Server是整個(gè)管道的 “龍頭” 。在上面的這個(gè)Hello World應(yīng)用中,在調(diào)用WebHostBuilder的Build方法創(chuàng)建一個(gè)WebHost之前,我們調(diào)用了它的一個(gè)擴(kuò)展方法UseKestrel,這個(gè)方法的作用就是為后續(xù)構(gòu)建的管道注冊(cè)一個(gè)名為KestrelServer的Server。
隨著WebHost的Start方法(當(dāng)我們調(diào)用WebHost的擴(kuò)展方法Run時(shí),它的Start方法會(huì)自動(dòng)被調(diào)用)的調(diào)用,定制的管道會(huì)被構(gòu)建出來(lái),管道的服務(wù)器將會(huì)綁定到一個(gè)預(yù)設(shè)的端口(比如KestrelServer默認(rèn)采用5000作為監(jiān)聽(tīng)端口)開(kāi)始監(jiān)聽(tīng)請(qǐng)求。HTTP請(qǐng)求一旦抵達(dá),Server會(huì)并將其標(biāo)準(zhǔn)并分發(fā)給管道后續(xù)的節(jié)點(diǎn),我們將管道中位于服務(wù)器之后的節(jié)點(diǎn)稱為“中間件(Middleware)”。每個(gè)中間件都具有各自獨(dú)立的功能,比如我們有專門實(shí)現(xiàn)路由功能的中間件,有專門實(shí)施用戶認(rèn)證的中間件。所謂的管道定制體現(xiàn)在根據(jù)具體的需求選擇對(duì)應(yīng)的中間件組成最終處理請(qǐng)求的管道。下圖揭示了由一個(gè)服務(wù)器和一組中間件構(gòu)成的請(qǐng)求處理管道。
一個(gè)建立在ASP.NET Core之上的應(yīng)用一般都是根據(jù)某個(gè)框架開(kāi)發(fā)的,一般來(lái)說(shuō),開(kāi)發(fā)框架本身就是通過(guò)某一個(gè)或者多個(gè)中間件構(gòu)建的。以ASP.NET Core MVC這個(gè)最著名的開(kāi)發(fā)框架為例,它實(shí)際上是借助于一個(gè)叫做 “路由” 的中間件實(shí)現(xiàn)了請(qǐng)求地址與Controller/Action之間的映射,并在此基礎(chǔ)實(shí)現(xiàn)了激活Controller、執(zhí)行Action以及呈現(xiàn)View等一系列的功能。所以應(yīng)用程序可以視為某個(gè)中間件的一部分,如果一定要將它獨(dú)立出來(lái),整個(gè)請(qǐng)求處理管道將呈現(xiàn)出如下圖所示的結(jié)構(gòu)。
?
三、管道的定制
在演示的Hello World程序中,我們?cè)谡{(diào)用擴(kuò)展方法UseKestrel注冊(cè)KestrelServer服務(wù)器之后,還調(diào)用WebHostBuilder如下一個(gè)名為Configure的擴(kuò)展方法注冊(cè)了一個(gè)類型為Action<IApplicationBuilder>的委托對(duì)象。從請(qǐng)求處理管道的角度來(lái)講,注冊(cè)這個(gè)委托對(duì)象的目的在于對(duì)構(gòu)建的管道進(jìn)行定制,說(shuō)得更加具體一點(diǎn),我們利用這個(gè)類型為管道注冊(cè)需要的中間件。演示實(shí)例中注冊(cè)的這個(gè)委托對(duì)象調(diào)用ApplicationBuilder的擴(kuò)展方法Run注冊(cè)了一個(gè)中間件來(lái)為每個(gè)請(qǐng)求響應(yīng)一個(gè) “Hello World” 字符串。
1: public?static IWebHostBuilder Configure(this IWebHostBuilder hostBuilder, Action<IApplicationBuilder> configureApp)除了通過(guò)調(diào)用WebHostBuilder的Configure方法注冊(cè)一個(gè)Action<IApplicationBuilder>類型的委托,注冊(cè)中間定義管道的邏輯更多地還是定義在一個(gè)單獨(dú)的類型中。由于管道的定制總是在應(yīng)用啟動(dòng)(Startup)的時(shí)候進(jìn)行,我們一般稱這個(gè)用于定制管道的類型為“啟動(dòng)類型”,并在大部分情況下會(huì)直接命名為Startup。按照約定,通過(guò)注冊(cè)中間件定制管道的操作會(huì)實(shí)現(xiàn)在名為Configure的方法中,方法的第一個(gè)參數(shù)類型必須是IApplicationBuilder接口,后面可定義任意數(shù)量和類型的參數(shù),當(dāng)這個(gè)方法被ASP.NET Core框架調(diào)用的時(shí)候,這些參數(shù)會(huì)采用依賴注入的方式來(lái)提供。啟動(dòng)類型可以通過(guò)調(diào)用WebHostBuilder的擴(kuò)展方法UseStartup<T>進(jìn)行注冊(cè),如下面的代碼與前面演示的實(shí)例是完全等效的。
1: public?class Program 2: { 3:???? public?static?void Main() 4:???? { 5:???????? new WebHostBuilder() 6:???????????? .UseKestrel() 7:???????????? .UseStartup<Startup>() 8:???????????? .Build() 9:???????????? .Run(); 10:???? } 11:???? public?class Startup 12:???? { 13:???????? public?void Configure(IApplicationBuilder app) 14:???????? { 15:???????????? app.Run(async context => await context.Response.WriteAsync("Hello World")); 16:???????? } 17:???? } 18: }在真正的項(xiàng)目開(kāi)發(fā)中,我們會(huì)利用ApplicationBuilder注冊(cè)相應(yīng)的中間件進(jìn)而構(gòu)建一個(gè)適合當(dāng)前請(qǐng)求處理需求的管道。如下面的代碼片段所示,我們除了按照如上的方式調(diào)用擴(kuò)展方法UseMvc注冊(cè)了支撐MVC框架的中間件(實(shí)際上是一個(gè)實(shí)現(xiàn)路由的中間件)之外,我們還通過(guò)調(diào)用其它的擴(kuò)展方法注冊(cè)了相應(yīng)的中間件實(shí)現(xiàn)了對(duì)靜態(tài)文件的訪問(wèn)(UseStaticFiles)、錯(cuò)誤頁(yè)面的呈現(xiàn)(UseExceptionHandler)以及基于ASP.NET Identity Framework的認(rèn)證(UseIdentity)。
1: public?class Startup 2: { 3:???? public?void Configure(IApplicationBuilder app) 4:???? { 5:???????? app.UseExceptionHandler("/Home/Error"); 6:???????? app.UseStaticFiles(); 7:???????? app.UseIdentity();?????????? 8:? 9:???????? app.UseMvc(); 10:???? } 11: }?
通過(guò)重建Hosting系統(tǒng)理解HTTP請(qǐng)求在ASP.NET Core管道中的處理流程[上]:采用管道處理請(qǐng)求
通過(guò)重建Hosting系統(tǒng)理解HTTP請(qǐng)求在ASP.NET Core管道中的處理流程[中]:管道如何處理請(qǐng)求
通過(guò)重建Hosting系統(tǒng)理解HTTP請(qǐng)求在ASP.NET Core管道中的處理流程[下]:管道如何創(chuàng)建
總結(jié)
以上是生活随笔為你收集整理的通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流程[上]:采用管道处理请求...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux文件名通配符:* ? [:di
- 下一篇: 几何画板应该这么用