協議升級機制

HTTP/1.1 協議 提供了一種特殊的機制,可用於使用 Upgrade 頭欄位將已建立的連線升級到不同的協議。

此機制是可選的;它不能用於堅持協議更改。即使實現支援新協議,也可以選擇不利用升級,並且在實踐中,此機制主要用於引導 WebSocket 連線。

另請注意,HTTP/2 明確禁止使用此機制;它特定於 HTTP/1.1。

升級 HTTP/1.1 連線

客戶端使用 Upgrade 頭欄位邀請伺服器切換到列出的協議之一,優先順序從高到低。

由於 Upgrade 是一個逐跳頭,因此也需要在 Connection 頭欄位中列出。這意味著包含 Upgrade 的典型請求看起來像這樣

http
GET /index.html HTTP/1.1
Host: www.example.com
Connection: upgrade
Upgrade: example/1, foo/2

根據請求的協議,可能需要其他標頭;例如,WebSocket 升級允許使用其他標頭來配置有關 WebSocket 連線的詳細資訊,以及在開啟連線時提供一定程度的安全保障。有關更多詳細資訊,請參閱 升級到 WebSocket 連線

如果伺服器決定升級連線,它將傳送回 101 Switching Protocols 響應狀態,其中包含一個指定正在切換到的協議的 Upgrade 頭。如果它不升級(或無法升級)連線,則它將忽略 Upgrade 頭併發送回常規響應(例如,200 OK)。

傳送 101 狀態程式碼後,伺服器就可以開始使用新協議進行通訊,並根據需要執行任何其他特定於協議的握手。實際上,一旦升級響應完成,連線就會變成一個雙向管道,並且可以在新協議上完成啟動升級的請求。

此機制的常見用途

在這裡,我們檢視 Upgrade 標頭的最常見用例。

升級到 WebSocket 連線

到目前為止,升級 HTTP 連線的最常見用例是使用 WebSockets,WebSockets 始終透過升級 HTTP 或 HTTPS 連線來實現。請記住,如果您使用 WebSocket API 或任何執行 WebSockets 的庫開啟新連線,則大部分或全部操作都將為您完成。例如,開啟 WebSocket 連線就像這樣簡單

js
webSocket = new WebSocket("ws://destination.server.ext", "optionalProtocol");

WebSocket() 建構函式會完成建立初始 HTTP/1.1 連線以及為您處理握手和升級過程的所有工作。

注意:您還可以使用 "wss://" URL 方案開啟安全的 WebSocket 連線。

如果您需要從頭開始建立 WebSocket 連線,則必須自己處理握手過程。建立初始 HTTP/1.1 會話後,需要透過向標準請求新增 UpgradeConnection 頭來請求升級,如下所示

http
Connection: Upgrade
Upgrade: websocket

WebSocket 特定標頭

以下標頭參與 WebSocket 升級過程。除了 UpgradeConnection 標頭之外,其餘標頭通常是可選的,或者在瀏覽器和伺服器相互通訊時由它們為您處理。

Sec-WebSocket-Extensions

指定一個或多個協議級 WebSocket 擴充套件,以要求伺服器使用。在一個請求中使用多個 Sec-WebSocket-Extension 標頭是允許的;結果與您在一個此類標頭中包含所有列出的擴充套件相同。

http
Sec-WebSocket-Extensions: extensions
extensions

要請求(或同意支援)的擴充套件的逗號分隔列表。這些應從 IANA WebSocket 副檔名稱登錄檔 中選擇。帶引數的擴充套件使用分號分隔符進行引數化。

例如

http
Sec-WebSocket-Extensions: superspeed, colormode; depth=16

Sec-WebSocket-Key

向伺服器提供確認客戶端有權請求升級到 WebSocket 所需的資訊。當不安全的(HTTP)客戶端希望升級時,可以使用此標頭,以便提供一定程度的防範濫用保護。金鑰的值是使用 WebSocket 規範中定義的演算法計算的,因此這不會提供安全性。相反,它有助於防止非 WebSocket 客戶端無意中或透過誤用請求 WebSocket 連線。因此,從本質上講,此金鑰確認“是的,我確實打算開啟一個 WebSocket 連線。”

此標頭由選擇使用它的客戶端自動新增;它無法使用 fetch()XMLHttpRequest.setRequestHeader() 方法新增。

http
Sec-WebSocket-Key: key
key

此升級請求的金鑰。如果客戶端希望執行此操作,則會新增此金鑰,伺服器將在響應中包含其自己的金鑰,客戶端將在將升級響應傳遞給您之前驗證該金鑰。

伺服器響應的 Sec-WebSocket-Accept 標頭的值將根據指定的 key 計算得出。

Sec-WebSocket-Protocol

Sec-WebSocket-Protocol 標頭指定一個或多個您希望使用的 WebSocket 協議,優先順序從高到低。伺服器支援的第一個協議將被選中,並由伺服器在響應中包含的 Sec-WebSocket-Protocol 標頭中返回。您可以在標頭中多次使用它,結果與您在一個標頭中使用子協議識別符號的逗號分隔列表相同。

http
Sec-WebSocket-Protocol: subprotocols
subprotocols

子協議名稱的逗號分隔列表,按優先順序排序。子協議可以從 IANA WebSocket 子協議名稱登錄檔 中選擇,也可以是客戶端和伺服器共同理解的自定義名稱。

Sec-WebSocket-Version

請求頭

指定客戶端希望使用的 WebSocket 協議版本,以便伺服器可以確認其端點是否支援該版本。

http
Sec-WebSocket-Version: version
version

客戶端在與伺服器通訊時希望使用的 WebSocket 協議版本。此數字應為 IANA WebSocket 版本號登錄檔 中列出的最新版本。WebSocket 協議的最新最終版本是版本 13。

響應頭

如果伺服器無法使用指定的 WebSocket 協議版本進行通訊,它將響應錯誤(例如 426 Upgrade Required),並在其標頭中包含一個 Sec-WebSocket-Version 標頭,其中包含支援的協議版本的逗號分隔列表。如果伺服器支援請求的協議版本,則響應中不包含 Sec-WebSocket-Version 標頭。

http
Sec-WebSocket-Version: supportedVersions
supportedVersions

伺服器支援的 WebSocket 協議版本的逗號分隔列表。

僅響應標頭

伺服器的響應可能包含這些。

Sec-WebSocket-Accept

在伺服器在開啟握手過程中傳送的響應訊息中包含,當伺服器願意啟動 WebSocket 連線時。它在響應標頭中最多出現一次。

http
Sec-WebSocket-Accept: hash
hash

如果提供了 Sec-WebSocket-Key 標頭,則此標頭的值是透過獲取金鑰的值、將字串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”連線到它、獲取該連線字串的 SHA-1 雜湊值(生成一個 20 位元組的值)來計算的。然後對該值進行 base64 編碼以獲取此屬性的值。

參考