OWIN 中文文件
OWIN:為 dotnet 開放的 web 服務介面
1 概述
本文對用於定義 OWIN
,OWIN
是 .NET web 服務和 web應用程式之間的一個標準介面。OWIN
的目標是用於服務與應用程式之間解耦【譯者注:使兩者間沒有強關聯,或者說相互不依賴】,並且成為一種開放規範,從而激勵.NET web
開發工具開源社群。
OWIN
是根據委託型別定義的,這兒沒有被稱作 OWIN.dll
或類似的程式集【譯者注:我的理解是這用於強調 OWIN
是規範(或協議),而不是具體實現】。在宿主或應用程式中實現 OWIN
規範不會使專案引入依賴。
在本文中,C#
Action
或 Func
語法被用於一些委託型別的定義。然而,這個委託型別
可以被 F#
native functions
、CLR interfaces
或 named delegates
同等表示【譯者注:由於不瞭解其它技術,所以使用了原文,但其表達的內容為委託型別在其它語言或技術中可以類似的定義,在此僅只是用C#
舉例】,這是經過精心設計的。在實現 OWIN
規範時,選擇一種(合適)委託表示使得其為你和你的堆疊工作。
以下關鍵詞"MUST"、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY"和"OPTIONAL” 按照 [RFC2119]{.underline}中的描述來理解。【譯者注:RFC 是計算機相關的各種說明】
2 定義
本文涉及到以下軟體角色:
2.1 服務
HTTP
服務直接與客戶端連線,接著使用 OWIN
語義處理請求。服務可能需要適配層(將請求)轉換為 OWIN
(識別的)語義。【譯者注:後文中"服務"如果沒有另外說明,都是這個意思】
2.2 Web 框架
在 OWIN
(管道)頂部的自包含(獨立的)元件,它對外暴露物件模型或者是API
,從而使得應用程式可以使用它來便利的
處理請求,Web Framework
可能需要適配層將 OWIN
語義轉換(為它識別的內容)。
2.3 Web 應用程式
一個具體的 Web
應用程式,可能構建在 Web Framework
(Web框架)的頂部,它使用 OWIN
相容的服務來執行。
2.4 中介軟體
在服務(server
)和應用程式之間構成的管道中的元件,元件出於某個目的檢查、路由或者修改請求和響應報文
2.5 宿主
應用程式和服務執行的程式,主要負責應用程式【OWIN
整體】的啟動(和關閉)。某些服務同時也是宿主【服務同時實現了宿主的功能】。
3 處理請求
一般來說,服務呼叫應用程式(提供環境字典引數,環境字典包含請求和響應的頭和內容);應用程式返回一個響應或指出錯誤。
3.1 應用程式委託
OWIN
中主要的介面稱為應用程式委託或 AppFunc
,應用程式委託使用IDictionary<string, object>
環境(字典),並且在處理完成時返回一個Task
。
//環境字典
using AppFunc = Func<IDictionary<string, object>,Task>; //方法完成時返回的任務【譯者注:Task是一種型別,後文中"任務"一般是該含義】
應用程式必須在最終完成時返回一個任務或丟擲異常。
3.2 環境(字典)
環境字典儲存關於請求、響應和(任何與服務狀態有關)的資訊。服務的職責是在請求和響應最初呼叫時提供它們的(報文)頭集合和(報文)體流。
應用程式接下來使用響應資料填充合適的欄位,然後寫響應體,最後在完成時返回響應。
(1)環境字典必須非空且可更改,而且必須包含下表中列出的鍵列表。
(2)鍵的比較(相等或不等)必須使用 StringComparer.Ordinal
(3)鍵對應的值必須非空,除非另有說明。
除了這些增加的鍵,宿主、服務、中介軟體和應用程式等可以向環境字典中新增任意與請求或響應有關的資料。
增加鍵的準則和常用鍵列表可以在 CommonKeys addendum
文件中找到。
3.2.1 請求資料
Required | Key Name | Value Description |
---|---|---|
Yes | owin.RequestBody |
A Stream with the request body, if any. Stream.Null MAY be used as a placeholder if there is no request body. See Request Body. |
Yes | owin.RequestHeaders |
An IDictionary<string, string[]> of request headers. See Headers. |
Yes | owin.RequestMethod |
A string containing the HTTP request method of the request (e.g., “GET”, “POST”). |
Yes | owin.RequestPath |
A string containing the request path. The path MUST be relative to the “root” of the application delegate. See Paths. |
Yes | owin.RequestPathBase |
A string containing the portion of the request path corresponding to the “root” of the application delegate; see Paths. |
Yes | owin.RequestProtocol |
A string containing the protocol name and version (e.g. “HTTP/1.0 ” or “HTTP/1.1 ”). |
Yes | owin.RequestQueryString |
A string containing the query string component of the HTTP request URI, without the leading “?” (e.g., “foo=bar&baz=quux ”). The value may be an empty string. |
Yes | owin.RequestScheme |
A string containing the URI scheme used for the request (e.g., “http”, “https”); see URI Scheme. |
3.2.2 響應資料
Required | Key Name | Value Description |
---|---|---|
Yes | owin.ResponseBody |
A Stream used to write out the response body, if any. See Response Body. |
Yes | owin.ResponseHeaders |
An IDictionary<string, string[]> of response headers. See Headers. |
No | owin.ResponseStatusCode |
An optional int containing the HTTP response status code as defined in RFC 2616 section 6.1.1. The default is 200. |
No | owin.ResponseReasonPhrase |
An optional string containing the reason phrase associated the given status code. If none is provided then the server SHOULD provide a default as described in RFC 2616 section 6.1.1 |
No | owin.ResponseProtocol |
An optional string containing the protocol name and version (e.g. “HTTP/1.0 ” or “HTTP/1.1 ”). If none is provided then the “owin.RequestProtocol ” key’s value is the default. |
3.2.3 其它資料
Required | Key Name | Value Description |
---|---|---|
Yes | owin.CallCancelled |
A CancellationToken indicating if the request has been canceled/aborted. See Request Lifetime. |
Yes | owin.Version |
A string indicating the OWIN version. See Versioning. |
【譯者注:以上3小節沒有翻譯,其它 HTTP報文一致,如有不瞭解,請查閱相關內容】
3.3 報文頭
HTTP
請求和響應報文頭都使用型別為 IDictionary<string, string[]>
的物件表示,以下要求在 RFC 2616 section 4.2 中有說明。
(1)字典必須可修改
(2)鍵必須是 HTTP
欄位名稱且沒有冒號或空格,多個單詞間用短橫線(-
)連線
(3)鍵的比較(相等或不等)必須使用 StringComparer.OrdinalIgnoreCase
(4)所有鍵值中的字元應該是 ASCII
碼錶中的
(5)返回的值陣列假定是原始資料的拷貝,任何想要修改值陣列的操作必須回溯到頭欄位,手動的使用headers[headerName] = modifiedArray;
或 headers.Remove(header)
語法操作。
(6)鍵對應的值都假定是混合的格式,比如 new string[1] {"value, value,value"}
,new string[3] {"value", "value", "value"}
, or
new string[2] {"value, value", "value"}
3種格式
(7)服務、應用程式和中間元件不應該拆分或合併非必要的報文頭中的值。雖然上述的3種格式都可以互相轉換,但實際上許多現有的實現只支援某種特定格式,開發人員應當通過選定或假定某種格式來靈活的支援現有的實現格式。
3.4 請求體、100 Continue 和已完成語義
當請求表明有請求體時,服務應當提供使用 owin.RequestBody
鍵訪問請求體流。如果期望沒有請求體資料 Stream.Null
可以作為佔位符被使用。
當請求 Expect
頭指明客戶端請求 100 Continue
,100 Continue
值由服務(決定是否)提供,應用程式禁止設定 owin.ResponseStatusCode
的值為100
,100 Continue
僅只用於中間響應,使用它將會阻止應用程式提供最終響應(比如:200 OK
)。在發生應用程式在請求體資料達到前讀取請求體流情況,服務應當代表應用程式傳送100 Continue
。
(1)應用程式委託在請求完成前不應當結束請求並返回任務,並把請求控制交給服務。一旦 AppFunc
完成應用程式不應當繼續從請求流中讀取資料。
(2)應用程式必須通過完成其返回的任務或丟擲異常來發出響應主體完成或失敗的訊號。在任務完成後,應用程式不應當向響應流中寫任何資料。
(3)如果在應用程式委託執行期間服務傳送 owin.CallCancelled
呼叫取消令牌,應用程式不應當嘗試再從請求流讀取資料,而應當迅速的完成應用程式委託任務。
(4)應用程式不應當關閉或釋放給定的(請求)流除非它完成了請求內容的使用。請求流的擁有者(比如服務或中介軟體)必須在應用程式委託任務完成時做必要的清理(工作)。
(5)任何從請求體流中丟擲的異常【】都是致命的,而是應當通過在 AppFunc
中(同步)丟擲(異常)或使用給定的異常致使非同步任務失敗來實現。
3.5 響應體
服務在初始化環境字典是提供 owin.ResponseBody
鍵訪問的請求體流。響應頭、狀態、說明片語等在第一次寫入響應體前都是可以修改的。
在第一次寫入時,服務驗證和方式響應頭,應用程式可以選擇緩衝響應資料來延遲響應頭確定。
(1)應用程式必須通過完成其返回的任務或丟擲異常來發出響應主體完成或失敗的訊號。在任務完成後,應用程式不應當向響應流中寫任何資料。
(2)如果在應用程式委託執行期間服務傳送 owin.CallCancelled
呼叫取消令牌,應用程式不應當嘗試再從請求流讀取資料,而應當迅速的完成應用程式委託任務。
(3)應用程式不應當關閉或釋放給定的(請求)流除非它完成了請求內容的使用。請求流的擁有者(比如服務或中介軟體)必須在應用程式委託任務完成時做必要的清理(工作)。應用程式不應當假定給定的流支援多個未完成的非同步寫操作。應用開發者應當在嘗試使用這種方式前驗證服務和所以在使用的中介軟體支援這種模式。
3.6 請求生命週期
請求完整範圍或生命週期受到一些因素的限制,包含客戶端、服務和應用程式委託。在最簡單的場景中,一個請求生命週期結束是在應用程式委託完成和服務正常的結束請求。任何級別的錯誤可能導致請求過早的結束,或者可能在內部處理和允許請求繼續(執行)。
owin.CallCancelled
鍵與取消呼叫令牌關聯,當請求(需要)終止時服務使用其作為(終止請求)訊號。如果在AppFunc
任務完成前請求出現錯誤
這個(訊號)應當被觸發。也應當在提供商決定的任何(時間)點觸發。中介軟體可以使用自己的(令牌)來替換它從而提供額外的粒度或功能,但他們應該把新令牌鏈到原始令牌上。
4 應用程式啟動
當宿主程式啟動時,它通過一系列的步驟來設定應用程式。
-
宿主建立屬性
IDictionary<string,object>
,並且填充屬性中所有啟動資料或功能。 -
宿主選擇將被使用的服務,並且提供將屬性集合提供給它,所以宿主可以近似的宣稱擁有任意的功能。
-
宿主定位應用程式啟動類,並且提供屬性集合來呼叫啟動程式。
-
應用程式讀取或者設定屬性集合中的配置,構造想要的請求處理管道,並且返回應用程式委託結果【返回】。
-
宿主使用給定的應用程式委託和屬性集合呼叫服務啟動類,服務自己完成配置,開始接受請求,並且呼叫應用程式委託來處理這些請求。屬性字典被設計為支援宿主、服務、中介軟體或應用程式用於讀取或設定任何配置引數。
(1)啟動屬性字典必須非空、可修改和必須包含下表要求的鍵列表
(2)鍵比較必須使用 StringComparer.Ordinal
(3)鍵對應的值必須非空,除非另有說明
除了這些鍵,宿主、服務、中介軟體和應用程式等可以向屬性字典新增任意與應用程式配置有關的資料。
新增鍵的準則和通用鍵定義列表可以在 CommonKeys addendum
規範中找到。
5.URI 重建
應用程式通常需要重建請求的完整 URI
的能力,這個過程不可能完美,因為 HTTP
客戶端通常傳送不完整的 URI
請求,但是 OWIN
為構建近似於(完整) URI
意圖提供了選擇。
5.1 URI 方案
HTTP
客戶端通常不會傳送 URI
方案資訊,並且依靠網路配置,OWIN
服務也許不能推斷出它的正確值。
在這些情形下,服務也許必須手動的配置或計算出一個值。
(1)服務必須為 owin.RequestScheme
提供一個最佳的猜測值
5.2 主機名稱
在 HTTP/1.1
請求的上下文中,客戶端發出請求的伺服器的名稱通常在請求的主機頭欄位值中表明,儘管它可能使用絕對請求URI
來指定(詳見 2616, sections 5.1.2, 19.6.1.1)。
【譯者注:示例:GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1】
服務必須在請求頭字典中為 Host
鍵提供一個值,值的格式必須是<hostname>[:<port>]
。
這個值應當被宿主通過以下步驟來獲取:
-
如果傳入請求的
URL
是絕對URL
,則Host
鍵對應的值必須是絕對URL
中Host
部分。 -
如果傳入請求的
URL
不是絕對URL
,則Host
鍵對應的值必須採用傳入請求頭Host
欄位的值。 -
如果傳入請求的
Host
欄位沒有值,或者它的值是空白,則服務必須為Host
鍵對應的值提供合理的最佳猜測值。
5.3 路徑
服務需要具有將應用程式委託對映到一些基礎路徑的能力。比如,服務可能有應用程式委託設定響應以"/my-app
“開頭的請求,在這種情形下環境字典中”owin.RequestPathBase
“的值應當設定為”/my-app
"。如果這個服務收到"/my-app/foo
“請求,則環境字典中”owin.RequestPath
“的值應當設定為”/foo
"。
(1)環境字典中"owin.RequestPathBase
"的值禁止使用斜杆結尾,並且必須以斜杆開始或者值是String.Empty
(2)環境字典中"owin.RequestPath
“的值必須使用斜杆開始,或者當”owin.RequestPathBase
"不是String.Empty
時,它可以是 String.Empty
5.4 URI 重構演算法
下面的演算法可以被用於構建近似完整請求 URI:
var uri =(string)Environment["owin.RequestScheme"] +"://" +Headers["Host"].First() +
(string)Environment["owin.RequestPathBase"] +
(string)Environment["owin.RequestPath"];
if(Environment["owin.RequestQueryString"] != "")
{
uri += "?" + (string)Environment["owin.RequestQueryString"];
}
上面的結果可能與客戶端傳送請求使用的 URI
不相同;比如,服務可能進行一些重寫來規範請求。
此外,這個主題在 URI Scheme and Hostname sections 中有附加說明。
5.5 百分比編碼
URI
使用百分比編碼來傳輸被允許使用之外的字元。百分比編碼是被用於 URI
元件中的8位編碼,這8位編碼通過
UTF-8
編碼產生。大多數的 Web 伺服器會在請求路徑中實現百分比編碼(see: RFC2616 section 5.1.2, also 3.2.3),並且 OWIN
遵從這個預設規則。在 OWIN中請求查詢字串以百分比編碼形式呈現。一個百分比編碼查詢字串可以包含’?‘或’='字元,這將導致查詢字串不可理解。
(1)服務必須為"owin.RequestPath
" 和 "owin.RequestPathBase
"的值提供百分比編碼後的值
(2)服務必須為 "owin.RequestQueryString"
的值提供百分比編碼後的值
6 錯誤處理
儘管這兒有些標準的異常(比如: ArgumentException
和 IOException
),可能在正常的請求處理場景中可以預見發生。
但僅只處理這些異常對於建立健壯的服務或應用程式是不夠的。如果服務希望健壯,它應該一致的處理所有型別的異常,這些異常由應用程式委託或報文體委託丟擲或返回。處理機制(比如寫日誌、崩潰、重啟和內部處理等)取決於服務和宿主程式。
6.1 應用程式錯誤
應用程式可能在以下位置產生異常:
(1)應用程式委託執行中丟擲的異常
(2)由應用程式委託的返回任務提供
應用程式應當嘗試處理內部異常,產生一個合適的響應(可能是 500
級別)而不是把異常傳遞給服務。
在應用程式提供響應後,服務應當在向底層協議寫響應頭前至少接收到一個向響應(體)流的寫。提供這種方式,如果服務獲取到應用程式委託任務的異常替代(原本)流的寫入。服務仍能產生一個500
級別的響應。
如果服務得到第一個向流的寫操作,它可以安全的假定應用程式在內部就可能的處理了很多的異常,服務可以開始傳送響應。
如果後續接收到異常,服務將視情況處理它。
6.2 服務錯誤
如果服務在請求生命週期中發生錯誤,它應該向 owin.CallCancelled
提供取消呼叫令牌。
服務可以任何必要行為來終止請求,但是它應該包容應用程式委託完成的延遲。
相關文章
- Owin知識
- tailwindcss中文文件AICSS
- octobercms 中文文件
- JointJS中文文件JS
- mongoose中文文件Go
- FluentPDO 中文文件
- Registrator中文文件
- Puppeteer 中文文件
- Nextjs中文文件NextJS
- aiohttp中文文件AIHTTP
- OWIN Middleware開發入門
- Ace editor中文文件
- Laravel Package 中文文件LaravelPackage
- JSON Editor 中文文件JSON
- Ocelot中文文件-管理
- Julia 1.0 中文文件
- Elasticsearch6.5中文文件-刪除文件Elasticsearch
- rust庫-ouroboros中文文件RustROS
- LaTeX 編寫中文文件
- PHP-redis中文文件PHPRedis
- Xdebug中文文件-目錄
- sharp.js中文文件JS
- 【Python】官方文件中文版Python
- SnapKit 中文文件翻譯APK
- Ocelot中文文件-認證
- Ocelot中文文件-快取快取
- LVGL|lvgl中文手冊(lvgl中文文件教程)
- Owin Katana 的底層原始碼分析原始碼
- C++ Mincrosoft的中文文件C++ROS
- BackTrader 中文文件(二十六)
- BackTrader 中文文件(二十七)
- BackTrader 中文文件(二十八)
- BackTrader 中文文件(二十九)
- [開發文件]bootstrap中文手冊boot
- 有symfony(symphony)中文文件嗎
- HTTPie 官方文件中文翻譯版HTTP
- Airflow 中文文件:快速開始AI
- Gin 框架中文文件(翻譯)框架