OWIN 是 Open Web Server Interface for .NET 的首字母縮寫,他的定義如下:
OWIN 在.NET Web Servers 與 Web Application 之間定義了一套標(biāo)準(zhǔn)接口,OWIN 的目標(biāo)是用于解耦 Web Server 和 Web Application?;诖藰?biāo)準(zhǔn),鼓勵開發(fā)者開發(fā)簡單、靈活的模塊,從而推進(jìn).NET Web Development 開源生態(tài)系統(tǒng)的發(fā)展。
正如你看到的這樣,OWIN 是接口、契約,而非具體的代碼實現(xiàn),僅僅是規(guī)范([specifications][1]),所以要實現(xiàn)自定義基于 OWIN 的 Web Server 必須要實現(xiàn)此規(guī)范。
歷時兩年(2010-2012),OWIN 的規(guī)范終于完成并且當(dāng)前版本是 1.0,在 OWIN 的官網(wǎng)上可以看到更具體的信息。
過去,IIS 作為.NET 開發(fā)者來說是最常用的 Web Server(沒有之一),源于微軟產(chǎn)品的緊耦合關(guān)系,我們不得不將 Website、Web Application、Web API 等部署在 IIS 上,事實上在 2010 年前并沒有什么不妥,但隨著近些年來 Web 的發(fā)展,特別是移動互聯(lián)網(wǎng)飛速發(fā)展,IIS 作為 Web Server 已經(jīng)暴露出他的不足了。主要體現(xiàn)在兩個方面,ASP.NET (System.Web)緊耦合 IIS,IIS 緊耦合 OS,這就意味著,我們的 Web Framework 必須部署在微軟的操作系統(tǒng)上,難以跨平臺。
我們知道,不管是 ASP.NET MVC 還是 ASP.NET WEB API 等都是基于 ASP.NET Framework 的,這種關(guān)系從前綴就可以窺倪出來。而 ASP.NET 的核心正是 System.Web 這個程序集,而且 System.Web緊耦合 IIS,他存在于.NET Framework 中。所以,這導(dǎo)致了 Web Framework 嚴(yán)重的局限性:
所以要想獲取最新的 Web Framework 是非常麻煩的,幸運(yùn)的事,微軟已經(jīng)意識到了問題的嚴(yán)重性,最新的 Web Framework 都是通過 Nuget 來獲取。
當(dāng)然這是一部分原因,還有一層原因是 ASP.NET & IIS 實在太過于笨重,如何講呢?
復(fù)雜的生命周期已成為累贅?簡單來說,當(dāng)請求到達(dá)服務(wù)器時,Windows 內(nèi)核組件 HTTP.SYS 組件捕獲請求,他會分析請求并決定是否交給 IIS 來處理,當(dāng)請求到達(dá) IIS 之后,IIS 會根據(jù)處理程序映射來匹配請求并交給對應(yīng)的程序集(實現(xiàn)了 ISAPI 接口,比如我們熟知的 aspnet_isapi.dll 是專門用來處理 ASP.NET Application)處理,最后加載了 CLR 運(yùn)行環(huán)境,將請求交給 aspnet_wp.exe 去處理,這時復(fù)雜的 ASP.NET 生命周期往往令人頭大,但事實上有很多時候我們并不需要他。
如下圖所示 ASP.NET Architecture:
http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter6/2.png" alt="" />
打開 IIS,你會發(fā)現(xiàn)他提供了非常豐富的功能:緩存、身份驗證、壓縮、加密等。但隨著移動互聯(lián)網(wǎng)蓬勃的發(fā)展,特別是 HTML 5 越來越成熟的今天,我們看到越來越多的操作發(fā)生在客戶端,而不是沉重的從服務(wù)器產(chǎn)生 HTML 返回,更多的是通過異步 **AJAX** 返回原生的數(shù)據(jù)。同理,對于 APP 來說我們只需要 Mobile Service 返回數(shù)據(jù)。顯然 IIS 顯得笨重了點,而且 IIS 作為微軟產(chǎn)品系的一環(huán),耦合程度太高。所以我們迫切需要輕量、快速、可擴(kuò)展的宿主來承載 Web Application 和 Web Service。
IIS 必須是安裝并運(yùn)行在 Windows 操作系統(tǒng)中,這是微軟產(chǎn)品的一貫風(fēng)格,環(huán)環(huán)相套,但不得不考慮他們的限制和局限性:
http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter6/3.png" alt="" />
這時你不得不去升級 IIS,但升級操作系統(tǒng)可能會引發(fā)舊系統(tǒng)的不穩(wěn)定性,所以要想平穩(wěn)的升級 IIS 并不是簡單的。
正是由于微軟產(chǎn)品系緊耦合的關(guān)系,才造成跨平臺上的不足,這也是被飽受詬病。所以我們需要**OWIN 來解耦,在面向?qū)ο蟮氖澜缋?,接口往往是解耦的關(guān)鍵,如下圖所示:**
http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter6/4.png" alt="" />
使用 OWIN,Web Framework 不再依賴 IIS 和 OS,這意味著你能使用任何你想的來替換 IIS(比如:Katana 或者 Nowin),并且在必要時隨時升級,而不是更新操作系統(tǒng)。當(dāng)然,如果你需要的話,你可以構(gòu)建自定義的宿主和 Pipeline 去處理 Http 請求。
這一切的改變都是由于OWIN 的出現(xiàn),他提供了明晰的規(guī)范以便我們快速靈活的去擴(kuò)展 Pipeline 來處理 Http 請求,甚至可以不寫任何一句代碼來切換不同的 Web Server,前提是這些 Web Server 遵循 OWIN 規(guī)范。
現(xiàn)在我們已經(jīng)了解了什么是 OWIN 已經(jīng)為什么需要 OWIN,現(xiàn)在是時候來分析一下 OWIN 的規(guī)范了。
實際上,OWIN 的規(guī)范非常簡單,他定義了一系列的層(Layer),并且他們的順序是以堆(Stack)的形式定義,如下所示。OWIN 中的接口被稱之為應(yīng)用程序委托或者 AppFunc,用來在這些層之間通信。
http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter6/5.png" alt="" />
OWIN 定義了 4 層:
Host:主要負(fù)責(zé)應(yīng)用程序的配置和啟動進(jìn)程,包括初始化 OWIN Pipeline、運(yùn)行 Server。
Server:這是實際的 Http Server,綁定套接字并監(jiān)聽的 HTTP 請求然后將 Request 和 Response 的 Body、Header 封裝成符合 OWIN 規(guī)范的字典并發(fā)送到 OWIN Middleware Pipeline 中,最后Application 為 Response Data 填充合適的字段輸出。
Middleware:稱之為中間件、組件,位于 Server 與 Application 之間,用來處理發(fā)送到 Pipeline 中的請求,這類組件可以是簡單的 Logger 或者是復(fù)雜的 Web Framework 比如 Web API、SignalR,只要 Sever 連接成功,Middleware 中間件可以是任何實現(xiàn)應(yīng)用程序委托的組件。
Application:這是具體的應(yīng)用程序代碼,可能在 Web Framework 之上。對于 Web API、SignalR這類 Web Framework 中間件而言,我們僅僅是改變了他們的托管方式,而不是取代 ASP.NET WEB API、SignalR 原先的應(yīng)用程序開發(fā)。所以該怎么開發(fā)就怎么開發(fā),只不過我們將他們注冊到 OWIN Pipeline 中去處理 HTTP 請求,成為 OWIN 管道的一部分,所以此處的 Application 即正在意義上的處理程序代碼。
OWIN 規(guī)范另一個重要的組成部分是接口的定義,用于 Server 和 Middleware 的交互。他并不是嚴(yán)格意義上的接口,而是一個委托并且每個 OWIN 中間件組件必須提供。
http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter6/6.png" alt="" />
從字面上理解,每個 OWIN 中間件在必須有一個方法接受類型了 IDictionary<string,object>的變量(俗稱環(huán)境字典),然后必須返回 Task 來異步執(zhí)行。
環(huán)境字典包含了 Request、Response 所有信息以及 Server State。通過 Pipeline,每個中間件組件和層都可以添加額外的信息,但環(huán)境字典定義了一系列強(qiáng)制必須存在的 Key,如下所示: http://wiki.jikexueyuan.com/project/think-in-asp-net-mvc/images/Chapter6/key.png" alt="" />
這些規(guī)范看起來可能簡單到微不足道,但 OWIN 的思想就是簡單、靈活——通過要求 OWIN 中間件只依賴 AppFun 類型,為開發(fā)基于 OWIN 的中間件提供了的最低門檻。同時,通過使用環(huán)境字典在各個中間件之間進(jìn)行信息的傳遞,而非傳統(tǒng) ASP.NET(System.Web)中使用 HttpContext 貫穿 ASP.NET 整個生命周期來傳遞。 既然 OWIN 是規(guī)范,而非真正實現(xiàn),所以是無法使用在項目中的,若要使用 OWIN,必須要實現(xiàn)他,所以這也是接下來我想聊的,OWIN 的實現(xiàn):Katana 。