協議升級機制
HTTP/1.1 協議提供了一種特殊的機制,可以使用 Upgrade 頭部欄位將已建立的連線升級到不同的協議。
這種機制是可選的;它不能用於強制協議更改。即使實現支援新協議,也可以選擇不利用升級,實際上,這種機制主要用於啟動 WebSocket 連線。
另請注意,HTTP/2 明確禁止使用此機制;它僅適用於 HTTP/1.1。
升級 HTTP/1.1 連線
Upgrade 頭部欄位由客戶端使用,以邀請伺服器切換到列出的協議之一,按偏好順序遞減。
由於 Upgrade 是一個逐跳頭部,它還需要在 Connection 頭部欄位中列出。這意味著包含 Upgrade 的典型請求將類似於
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,它總是透過升級 HTTP 或 HTTPS 連線來實現。請記住,如果您使用 WebSocket API 或任何執行 WebSockets 的庫開啟新連線,則大部分或全部工作都已為您完成。例如,開啟 WebSocket 連線是一個單一的方法
webSocket = new WebSocket("ws://destination.server.ext", "optionalProtocol");
WebSocket() 建構函式會完成建立初始 HTTP/1.1 連線,然後為您處理握手和升級過程的所有工作。
注意:您還可以使用 "wss://" URL 方案開啟安全的 WebSocket 連線。
如果您需要從頭開始建立 WebSocket 連線,則必須自己處理握手過程。建立初始 HTTP/1.1 會話後,您需要透過向標準請求新增 Upgrade 和 Connection 頭部來請求升級,如下所示
Connection: Upgrade
Upgrade: websocket
WebSocket 特定頭部
以下頭部涉及 WebSocket 升級過程。除了 Upgrade 和 Connection 頭部之外,其餘的通常是可選的,或者在瀏覽器和伺服器相互通訊時由它們為您處理。
Sec-WebSocket-Extensions
指定一個或多個協議級 WebSocket 擴充套件,以請求伺服器使用。在請求中使用多個 Sec-WebSocket-Extension 頭部是允許的;結果與您將所有列出的擴充套件包含在一個此類頭部中相同。
Sec-WebSocket-Extensions: extensions
擴充套件-
以逗號分隔的請求(或同意支援)擴充套件列表。這些應從 IANA WebSocket 副檔名稱登錄檔中選擇。帶引數的擴充套件使用分號分隔。
例如,此頭部指示兩個自定義擴充套件:superspeed 和 colormode(還包含引數 depth=16)
Sec-WebSocket-Extensions: superspeed, colormode; depth=16
Sec-WebSocket-Key
向伺服器提供所需資訊,以確認客戶端有權請求升級到 WebSocket。當不安全的(HTTP)客戶端希望升級時,可以使用此頭部,以提供一定程度的防止濫用的保護。金鑰的值是使用 WebSocket 規範中定義的演算法計算的,因此這不提供安全性。相反,它有助於防止非 WebSocket 客戶端無意中或透過濫用請求 WebSocket 連線。因此,本質上,此金鑰確認“是的,我確實打算開啟一個 WebSocket 連線。”
此頭部由選擇使用它的客戶端自動新增;它不能使用 fetch() 或 XMLHttpRequest.setRequestHeader() 方法新增。
Sec-WebSocket-Key: key
key-
此請求升級的金鑰。如果客戶端希望這樣做,它會新增此金鑰,伺服器將在響應中包含自己的金鑰,客戶端在向您傳送升級響應之前將驗證該金鑰。
伺服器響應的 Sec-WebSocket-Accept 頭部將具有根據指定 key 計算的值。
Sec-WebSocket-Protocol
Sec-WebSocket-Protocol 頭部按偏好順序指定您希望使用的一個或多個 WebSocket 協議。伺服器支援的第一個協議將被伺服器選擇並在響應中包含的 Sec-WebSocket-Protocol 頭部中返回。您也可以在頭部中多次使用此頭部;結果與您在單個頭部中使用逗號分隔的子協議識別符號列表相同。
Sec-WebSocket-Protocol: subprotocols
子協議-
以逗號分隔的子協議名稱列表,按偏好順序排列。子協議可以從 IANA WebSocket 子協議名稱登錄檔中選擇,也可以是客戶端和伺服器共同理解的自定義名稱。
Sec-WebSocket-Version
請求頭
指定客戶端希望使用的 WebSocket 協議版本,以便伺服器可以確認其端是否支援該版本。
Sec-WebSocket-Version: version
版本-
客戶端在與伺服器通訊時希望使用的 WebSocket 協議版本。此數字應為 IANA WebSocket 版本號登錄檔中列出的最新版本。WebSocket 協議的最新最終版本是版本 13。
響應頭
如果伺服器無法使用指定版本的 WebSocket 協議進行通訊,它將返回一個錯誤(例如 426 Upgrade Required),其頭部包含一個 Sec-WebSocket-Version 頭部,其中包含支援的協議版本列表,以逗號分隔。如果伺服器支援請求的協議版本,則響應中不包含 Sec-WebSocket-Version 頭部。
Sec-WebSocket-Version: supportedVersions
supportedVersions-
以逗號分隔的伺服器支援的 WebSocket 協議版本列表。
僅響應頭部
伺服器的響應可能包含這些。
Sec-WebSocket-Accept
在伺服器願意啟動 WebSocket 連線時,在開啟握手過程中包含在伺服器的響應訊息中。它在響應頭部中最多出現一次。
Sec-WebSocket-Accept: hash
雜湊-
如果提供了
Sec-WebSocket-Key頭部,則此頭部的值是透過獲取金鑰的值,將其與字串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”連線,然後對連線後的字串進行 SHA-1 雜湊計算,得到一個 20 位元組的值。然後將該值進行 base64 編碼以獲取此屬性的值。
規範
| 規範 |
|---|
| WebSocket 協議 |
| 超文字傳輸協議 (HTTP/1.1): 訊息語法和路由 |
| 超文字傳輸協議版本 2 (HTTP/2) |