要建立WebSocket連接,客戶端打開一個(gè)連接并發(fā)送一個(gè)握手,就像本節(jié)中定義那樣。一個(gè)連接最初被定義為一個(gè)CONNECTING狀態(tài)??蛻舳藢⑿枰峁┮粋€(gè)/host/、/port/、/resource name/、和/secure/標(biāo)記,它們都是在第三章討論的WebSocket URI的組件,連同一起使用的一個(gè)/protocols/和/extensions/列表。此外,如果客戶端是一個(gè)web瀏覽器,它提供/origin/??蛻舳诉\(yùn)行在一個(gè)受控環(huán)境,例如綁定到特定運(yùn)營商的手機(jī)上的瀏覽器,可以下移(offload)連接管理到網(wǎng)絡(luò)上的另一個(gè)代理。在這種情況下,用于本規(guī)范目的的客戶端被認(rèn)為包括手機(jī)軟件和任何這樣的代理。
當(dāng)客戶端要建立一個(gè)WebSocket連接,給定一組(/host/、/port/、/resource name/、和/secure/標(biāo)記)、連同一起使用的一個(gè)/protocols/和/extensions/列表、和在web瀏覽器情況下的一個(gè)/origin/,它必須打開一個(gè)連接、發(fā)送一個(gè)打開階段握手、并讀取服務(wù)器響應(yīng)中的握手。應(yīng)如何打開連接的確切要求、在打開階段握手應(yīng)發(fā)送什么、以及應(yīng)如何解釋服務(wù)器響應(yīng),在本節(jié)如下所述。在下面的文本中,我們將使用第三章的術(shù)語,如定義在那章的“/host” 、和“/sucure/標(biāo)記” 。
傳入該算法的WebSocket URI組件(/host/、/port/、/resource name/、和/secure/ 標(biāo)記) 根據(jù)指定在第3章的WebSocket URI規(guī)范,必須是有效的。如果任何組件是無效的,客戶端必須失敗WebSocket連接并終止這些步驟。
如果客戶端已經(jīng)有一個(gè)到通過主機(jī)/host/和端口/port/對(duì)標(biāo)識(shí)的遠(yuǎn)程主機(jī)(IP地址)的WebSocket連接,即使遠(yuǎn)程主機(jī)是已知的另一個(gè)名字,客戶端必須等待直到連接已建立或由于連接已失敗。必須不超過一個(gè)連接處于CONNECTING 狀態(tài)。如果同時(shí)多個(gè)連接到同一個(gè)IP地址,客戶端必須 序列化它們,以致一次不多于一個(gè)連接在以下步驟中運(yùn)行。
如果客戶端不能決定遠(yuǎn)程主機(jī)的IP地址(例如,因?yàn)樗型ㄐ攀峭ㄟ^代理服務(wù)器本身進(jìn)行DNS查詢),那么客戶端必須假定這步的目的是每一個(gè)主機(jī)名引用一個(gè)不同遠(yuǎn)程主機(jī),且相反,客戶端應(yīng)該限制同時(shí)掛起的連接總數(shù)為一個(gè)適當(dāng)?shù)偷臄?shù)(例如,客戶端可能允許到a.example.com和b.example.com同時(shí)掛起連接,但如果30個(gè)同時(shí)連接到同一個(gè)請(qǐng)求的主機(jī),那可能是不允許的)。例如,在一個(gè)web瀏覽器上下文中,客戶端需要考慮用戶已經(jīng)打開的標(biāo)簽數(shù)量,在設(shè)置同時(shí)掛起的連接數(shù)量的限制時(shí)。
注意:這使得它很難僅通過打開大量的WebSocket連接到遠(yuǎn)程主機(jī)為腳本執(zhí)行一個(gè)拒絕服務(wù)攻擊。當(dāng)攻擊在關(guān)閉連接之前被暫停時(shí),服務(wù)器可以進(jìn)一步降低自身的負(fù)載,因?yàn)檫@將降低客戶端重新連接的速度。
注意:沒有限制一個(gè)客戶端可以與單個(gè)遠(yuǎn)程主機(jī)有的已建立的WebSocket連接數(shù)量。服務(wù)器可以拒絕接受來自具有大量的現(xiàn)有連接的主機(jī)/IP地址的連接或當(dāng)遭受高負(fù)載時(shí)斷開占用資源的連接。
使用代理:當(dāng)有WebSocket協(xié)議連接主機(jī)/host/和端口/port/時(shí),如果客戶端配置使用代理,那么客戶端應(yīng)該連接到代理并要求它打開一個(gè)到由/host/給定主機(jī)和/port/給定端口的TCP連接。 例子:例如,如果客戶端為所有信息傳輸使用一個(gè)HTTP代理,那么如果它試圖連接到服務(wù)器example.com的80端口,它可能會(huì)發(fā)送以下行到代理服務(wù)器:
CONNECT example.com:80 HTTP/1.1
Host: example.com
如果還有密碼,連接可能看起來像:
CONNECT example.com:80 HTTP/1.1
Host: example.com
Proxy-authorization: Basic ZWRuYW1vZGU6bm9jYXBlcyE=
如果客戶端沒有配置使用一個(gè)代理,那么應(yīng)該打開一個(gè)直接TCP連接到由/host/給定的主機(jī)和/port/給定的端口。
注意:不暴露明確的UI來為WebSocket連接選擇一個(gè)獨(dú)立于其他代理的代理實(shí)現(xiàn),鼓勵(lì)使用SOCKS5[RFC1928]代理用于WebSocket連接,如果有的話,或做不到這一點(diǎn),選擇為HTTPS連接配置代理勝過為HTTP連接配置代理。
為了代理自動(dòng)配置腳本,傳給函數(shù)的URI必須從/host/、/port/、/resource name/、和/secure/標(biāo)記來構(gòu)造,使用第三章給定的WebSocket URI定義。
注意:WebSocket協(xié)議可以在代理自動(dòng)配置腳本中從模式中識(shí)別(“ws”用于未加密的連接和“wss”用于加密的連接)。
如果連接無法打開,或者因?yàn)橹苯舆B接失敗或者因?yàn)槿魏问褂玫拇矸祷匾粋€(gè)錯(cuò)誤,那么客戶端必須失敗WebSocket連接并終止連接嘗試。
客戶端必須在TLS握手中使用服務(wù)器命名指示(Server Name Indication)擴(kuò)展[RFC6066]。
一旦一個(gè)到服務(wù)器的連接連接(包括通過代理或在TLS加密隧道之上的連接),客戶端必須發(fā)送一個(gè)打開階段握手到服務(wù)器。該握手包括一個(gè)HTTP Upgrade請(qǐng)求,連同一個(gè)必需的和可選的頭字段列表。該握手的要求如下所示。
握手必須是像[RFC2616]指定的那樣的有效的HTTP請(qǐng)求。
請(qǐng)求方法必須是GET、且HTTP版本必須是至少1.1。
例如,如果WebSocket URI是“ws://example.com/chat”,發(fā)送的第一行應(yīng)該是“GET /chat HTTP/1.1”。
請(qǐng)求的“Request-URI”部分必須匹配定義在第三章的(一個(gè)相對(duì)URI)/resource name/或是一個(gè)絕對(duì)的http/https URI,當(dāng)解析時(shí),有一個(gè)/resource name/、/host/、和/port/匹配相應(yīng)的ws/wss URI。
請(qǐng)求必須包含一個(gè)|Host|頭字段,其值包含/host/加上可選的“:”后跟/port/(當(dāng)沒用默認(rèn)端口時(shí))。
請(qǐng)求必須包含一個(gè)|Upgrade|頭字段,其值必須包含“websocket”關(guān)鍵字。
請(qǐng)求必須包含一個(gè)|Connection|頭字段,其值必須包含“Upgrade”標(biāo)記。
請(qǐng)求必須包含一個(gè)名字為| Sec-WebSocket-Key |的頭字段,這個(gè)頭字段的值必須是臨時(shí)(nonce)組成的一個(gè)隨機(jī)選擇的已經(jīng)base64編碼的(參見[RFC4648]第4章)16位的值。臨時(shí)必須是為每個(gè)連接隨機(jī)選擇的。
注意:作為一個(gè)例子,如果隨機(jī)選擇的值是字節(jié)序列0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x10,頭字段的值必須是“AQIDBAUGBwgJCgsMDQ4PEC==”
如果請(qǐng)求來自一個(gè)瀏覽器客戶端,請(qǐng)求必須包含一個(gè)名字為|Origin|[RFC6454]的頭字段。如果連接是來自非瀏覽器客戶端,如果該客戶端的語義匹配描述在這的用于瀏覽器的使用情況時(shí),請(qǐng)求可以包含這個(gè)字段。該頭字段的值是在建立正運(yùn)行的連接代碼中的環(huán)境的origin 的ASCII序列化。參考[RFC6454]獲取如果構(gòu)造該頭字段的值的詳細(xì)信息。
作為一個(gè)例子,如果從www.example.com下載的代碼試圖建立到ww2.example.com的連接,該頭字段的值將是“http://www.example.com”。
請(qǐng)求必須包含一個(gè)名字為|Sec-WebSocket-Version|的頭字段。該頭字段的值必須是13。
注意:盡管本文檔的草案版本(-09、-10、-11、和-12)發(fā)布了(它們多不是編輯上的修改和澄清而不是改變電報(bào)協(xié)議[wire protocol]),值9、10、11、和12不被用作有效的Sec-WebSocket-Version。這些值被保留在IANA注冊(cè)中心,但并將不會(huì)被使用。
請(qǐng)求可以包含一個(gè)名字為|Sec-WebSocket-Protocol|的頭字段。如果存在,該值表示一個(gè)或多個(gè)逗號(hào)分割的客戶端想要表達(dá)的子協(xié)議,按優(yōu)先順序排列。包含該值的元素必須是非空字符串,且字符在U+0021到U+007E范圍內(nèi)但不包含定義在[RFC2616]中的分割字符且必須所有是唯一的字符串。用于該頭字段值的ABNF是1#token,其構(gòu)造和規(guī)則定義在[RFC2616]給出。
請(qǐng)求可以包含一個(gè)名字為|Sec-WebSocket-Extensions|的頭字段。如果存在,該值表示客戶端想要表達(dá)的協(xié)議級(jí)的擴(kuò)展。該頭字段的解釋和格式描述在第9.1節(jié)。
一旦客戶端的打開階段握手已經(jīng)發(fā)送,客戶端在發(fā)送任何進(jìn)一步數(shù)據(jù)之前必須等待自服務(wù)器的一個(gè)響應(yīng)??蛻舳吮仨汄?yàn)證服務(wù)器的響應(yīng),如下所示:
如果收到的服務(wù)器的狀態(tài)碼不是101,客戶端處理每個(gè)HTTP[RFC2616]程序的響應(yīng)。尤其是,如果收到一個(gè)401狀態(tài)碼客戶端可能執(zhí)行身份驗(yàn)證;服務(wù)器可能使用一個(gè)3xx狀態(tài)碼重定向客戶端(但客戶端不需要跟隨他們),等等。否則,按以下步驟處理。
如果響應(yīng)缺少一個(gè)|Upgrade|頭字段或|Upgrade|頭字段包含的值不是一個(gè)不區(qū)分大小寫的ASCII匹配值“websocket”,客戶端必須失敗WebSocket連接。
如果想要缺少一個(gè)|Connection|頭字段或|Connection|頭字段不包含一個(gè)不區(qū)分大小的ASCII匹配值“Upgrade”符號(hào),客戶端必須失敗WebSocket連接。
如果想要缺少一個(gè)|Sec-WebSocket-Accept|頭字段或|Sec-WebSocket-Accept|包含一個(gè)不是|Sec-WebSocket-Key|(一個(gè)字符串,不是base64編碼的)與字符串“258EAFA5- E914-47DA-95CA-C5AB0DC85B11”但忽略任何前導(dǎo)和結(jié)尾空格相關(guān)聯(lián)的base64編碼的SHA-1值,客戶端必須失敗WebSocket連接。
如果響應(yīng)包含一個(gè)|Sec-WebSocket-Extensions|頭字段且此頭字段表示使用一個(gè)擴(kuò)展但沒有出現(xiàn)在客戶端握手中(服務(wù)器表示的一個(gè)擴(kuò)展,不是客戶端請(qǐng)求的),客戶端必須失敗WebSocket連接。解析該頭字段以確定請(qǐng)求了哪些擴(kuò)展在9.1節(jié)討論。
如果服務(wù)器響應(yīng)不符合定義在本節(jié)和4.2.2節(jié)中的服務(wù)器握手的要求,客戶端必須失敗WebSocket連接。
請(qǐng)注意,根據(jù)[RFC2616],所有命名在HTTP請(qǐng)求和HTTP響應(yīng)中的頭字段是不區(qū)分大小寫的。
如果服務(wù)器響應(yīng)驗(yàn)證了以上提供的,這是說,WebSocket連接建立了且WebSocket連接處于OPEN狀態(tài)。使用中的擴(kuò)展被定義為一個(gè)(可能空的)字符串,其值等于服務(wù)器握手中提供的|Sec-WebSocket-Extensions|頭字段的值或如果在服務(wù)器握手中沒有該頭字段則為null值。使用中的子協(xié)議被定義為服務(wù)器握手中的|Sec-WebSocket-Protocol|頭字段的值或如果在服務(wù)器握手中沒有該頭字段則為null值。另外,如果在服務(wù)器握手中表示cookie應(yīng)該被設(shè)置(定義在[RFC6265])的任何頭字段,這些cookie被稱為在服務(wù)器打開階段握手期間的Cookie設(shè)置。
服務(wù)器可以下移(offload)連接管理到網(wǎng)絡(luò)上的其他代理,例如,負(fù)載均衡和反向代理。在這樣的情況下,用于本規(guī)范的目的的服務(wù)器被認(rèn)為是包括服務(wù)器端基礎(chǔ)設(shè)施的所有部分,從開始的設(shè)備到終止TCP連接,處理請(qǐng)求和發(fā)送響應(yīng)的服務(wù)器的所有方式。
例如:一個(gè)數(shù)據(jù)中心可能有一個(gè)用適當(dāng)?shù)奈帐謥眄憫?yīng)WebSocket請(qǐng)求的服務(wù)器,并接著傳遞連接到另一個(gè)服務(wù)器來真正處理數(shù)據(jù)幀。對(duì)于本規(guī)范的目的,“服務(wù)器”是結(jié)合了兩種計(jì)算機(jī)。
當(dāng)客戶端開始一個(gè)WebSocket連接,它發(fā)送它的打開階段握手部分。服務(wù)器必須至少解析這個(gè)握手為了獲取必要的信息來生成服務(wù)器握手部分。
客戶端打開階段握手包括以下部分。如果服務(wù)器,當(dāng)讀取握手時(shí),發(fā)現(xiàn)客戶端沒有發(fā)送一個(gè)匹配下面描述的握手(注意,按照[RFC2616],頭字段順序是不重要的),包括但不限制任何違反ABNF語法指定的握手組件,服務(wù)器必須停止處理客戶端握手并返回一個(gè)具有一個(gè)適當(dāng)錯(cuò)誤碼的(例如400錯(cuò)誤的請(qǐng)求)HTTP響應(yīng)。
一個(gè)HTTP/1.1或更高版本的GET請(qǐng)求,包括一個(gè)“Request-URI” [RFC2616]應(yīng)該被解釋為定義在第3章的/resource name/(或一個(gè)包含/resource name/的絕對(duì)HTTP/HTTPS URI)。
一個(gè)|Host|頭字段包含服務(wù)器的權(quán)限。
一個(gè)|Upgrade|頭字段包含值“websocket”,視為一個(gè)不區(qū)分大小寫的ASCII值。
一個(gè)|Connection|頭字段包含符號(hào)“Upgrade”,視為一個(gè)不區(qū)分大小寫的ASCII值。
一個(gè)|Sec-WebSocket-Key|頭字段,帶有一個(gè)base64編碼的值(參見[RFC4648]第4章),當(dāng)解碼時(shí),長度是16字節(jié)。
一個(gè)|Sec-WebSocket-Version|頭字段,帶有值13。
可選的,一個(gè)|Origin|頭字段。該頭字段由所有瀏覽器客戶端發(fā)送。一個(gè)試圖缺失此頭字段的連接不應(yīng)該被解釋為來自瀏覽器客戶端。
可選的,一個(gè)|Sec-WebSocket-Protocol|頭字段,帶有表示客戶端想要表達(dá)的協(xié)議的值列表,按優(yōu)先順序排列。
可選的,一個(gè)|Sec-WebSocket-Extensions|頭字段,帶有表示客戶端想要表達(dá)的擴(kuò)展的值列表。此頭字段的解釋在9.1節(jié)討論。
當(dāng)客戶端建議一個(gè)到服務(wù)器的WebSocket連接,服務(wù)器必須完成以下步驟來接受該連接并發(fā)送服務(wù)器的打開階段握手。
如果連接發(fā)送在一個(gè)HTTPS (HTTP-over-TLS)端口上,在連接之上執(zhí)行一個(gè)TLS握手。如果失敗了(例如,在擴(kuò)展的客戶端hello“server_name”擴(kuò)展中的客戶端指示的一個(gè)主機(jī)名,服務(wù)器對(duì)主機(jī)不可用),則關(guān)閉該連接;否則,用于該連接的所有進(jìn)一步的通信必須貫穿加密的隧道[RFC5246]。
服務(wù)器可以執(zhí)行額外的客戶端身份認(rèn)證,例如,返回401狀態(tài)碼與描述在[RFC2616]中的相關(guān)的|WWW-Authenticate|頭字段。
服務(wù)器可以使用3xx狀態(tài)碼[RFC2616]重定向客戶端。注意,此步驟可能連同,之前,或之后的可選的上面描述的身份驗(yàn)證步驟一起發(fā)生。
/origin/
客戶端握手中的|Origin|頭字段表示建立連接的腳本的來源。Origin是序列化為ASCII并轉(zhuǎn)換為小寫。服務(wù)器可以使用這個(gè)信息作為決定是否接受傳入連接的一部分。如果服務(wù)器沒有驗(yàn)證origin,它將接受來自任何地方的連接。如果服務(wù)器不想接受這個(gè)連接,它必須返回一個(gè)適當(dāng)?shù)腍TTP錯(cuò)誤碼(例如,403 Forbidden)并中斷描述在本章中的WebSocket握手。更多詳細(xì)信息,請(qǐng)參閱第10章。
/key/
在客戶端握手中的|Sec-WebSocket-Key|頭字段包括一個(gè)base64編碼的值,如果解碼,長度是16字節(jié)。這個(gè)(編碼的)值用在創(chuàng)建服務(wù)器握手時(shí)來表示接受連接。服務(wù)器沒必要使用base64解碼|Sec-WebSocket-Key|值。
/version/
客戶端握手中的|Sec-WebSocket-Version|頭字段包括客戶端試圖通信的WebSocket協(xié)議的版本。如果該版本沒有匹配服務(wù)器理解的一個(gè)版本,服務(wù)器必須中斷描述在本節(jié)的WebSocket握手并替代返回一個(gè)適當(dāng)?shù)腍TTP錯(cuò)誤碼(例如,426 Upgrade Required)且一個(gè)|Sec-WebSocket-Version|頭字段表示服務(wù)器能理解的版本。
/resource name/
由服務(wù)器提供的服務(wù)的標(biāo)識(shí)符。如果服務(wù)器提供多個(gè)服務(wù),那么該值應(yīng)該源自客戶端我手中的GET方法的“Request-URI”中給定的資源名。如果請(qǐng)求的服務(wù)器不可用,服務(wù)器必須發(fā)生一個(gè)適當(dāng)?shù)腍TTP錯(cuò)誤碼(例如404 NotFound)并中斷WebSocket握手。
/subprotocol/
或者一個(gè)代表服務(wù)器準(zhǔn)備使用的子協(xié)議的單個(gè)值或者null。選擇的值必須源自客戶端握手,從|Sec-WebSocket-Protocol|字段具體地選擇一個(gè)值,服務(wù)器將使用它用于這個(gè)連接(如果有)。如果客戶端握手不包含這樣一個(gè)頭字段或如果服務(wù)器不同意任何客戶端請(qǐng)求的子協(xié)議,僅接受的值為null。這個(gè)字段不存在等價(jià)于null值(意思是如果服務(wù)器不想同意任何建議的子協(xié)議,它必須在它的響應(yīng)中不發(fā)送回一個(gè)|Sec-WebSocket-Protocol|頭字段)。用于這些目的,空字符串與null值是不一樣的,且它不是這個(gè)字段合法的值。用于該頭字段的值A(chǔ)BNF是(符號(hào)),構(gòu)造定義和規(guī)則在[RFC2616]中給出。
/extensions/
表示服務(wù)器準(zhǔn)備使用的協(xié)議級(jí)別擴(kuò)展的一個(gè)列表(可能為空)。如果服務(wù)器支持多個(gè)擴(kuò)展,那么該值必須源自客戶端握手,通過從|Sec-WebSocket-Extensions|字段具體地選擇一個(gè)或多個(gè)值。這個(gè)字段不存在等價(jià)于null值。用于這些目的,空字符串與null值是不一樣的??蛻粑戳谐龅臄U(kuò)展必須不被列出。那些值應(yīng)該被選擇和解釋的方法在9.1節(jié)討論。
如果服務(wù)器選擇接受傳入的連接,它必須以一個(gè)有效的表示以下的HTTP響應(yīng)應(yīng)答。
一個(gè)按照RFC2616[RFC2616]帶有101響應(yīng)碼的Status-Line。這樣的響應(yīng)可能看起來像“HTTP/1.1 101 Switching Protocols”。
一個(gè)按照RFC2616[RFC2616]帶有值“websocket”的|Upgrade|頭字段。
一個(gè)帶有“Upgrade”的| Connection |頭字段。
該頭字段的ABNF[RFC2616]定義如下:
Sec-WebSocket-Accept = base64-value-non-empty
base64-value-non-empty = (1*base64-data [ base64-padding ]) |
base64-padding
base64-data = 4base64-character
base64-padding = (2base64-character "==") |
(3base64-character "=")
base64-character = ALPHA | DIGIT | "+" | "/"
注意:例如,如果客戶端握手中的|Sec-WebSocket-Key|頭字段的值是“dGhlIHNhbXBsZSBub25jZQ==”,服務(wù)器將追加字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”為字符串dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11形式。
服務(wù)器將采取SHA-1散列這個(gè)字符串,并給出值0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea。這個(gè)值接著base64編碼,給出值“s3pPLMBiTxaQ9kYGzzhZRbK+xOo=”,這將在|Sec-WebSocket-Accept|頭字段中被返回。
可選的,一個(gè)|Sec-WebSocket-Protocol|頭字段,帶有一個(gè)定義在4.2.2節(jié)第4步的值/subprotocol/。
可選的,一個(gè)|Sec-WebSocket-Extensions|頭字段,帶有一個(gè)定義在4.2.2節(jié)第4步的值/ extensions /。如果使用多個(gè)擴(kuò)展,那么可以把所有都列在一個(gè)|Sec-WebSocket-Extensions|頭字段中或者分配到|Sec-WebSocket-Extensions|頭字段的多個(gè)實(shí)例之間。 這就完成了服務(wù)器握手。如果服務(wù)器完整這些步驟且沒有中斷WebSocket握手,服務(wù)器認(rèn)為WebSocket連接已建立且WebSocket連接處于OPEN狀態(tài)。此時(shí),服務(wù)器可以開始發(fā)送(和接收)數(shù)據(jù)了。
本節(jié)使用的ABNF語法/規(guī)范來自[RFC2616]第2.1節(jié),包括“隱式*LWS規(guī)則”。
注意,以下ABNF約定用于本節(jié)中。一些規(guī)則的名相當(dāng)于相應(yīng)的頭字段名字。這樣的規(guī)則表示相應(yīng)的頭字段值,例如Sec-WebSocket-Key ABNF規(guī)則描述了|Sec-WebSocket-Key| 頭字段值的語法。在名字中帶有“-Client”后綴的ABNF規(guī)則僅用在由客戶端到服務(wù)器發(fā)送請(qǐng)求的情況;在名字中帶有“-Server”后綴的ABNF規(guī)則僅用在由服務(wù)器到客戶端發(fā)生響應(yīng)的情況。例如,ABNF規(guī)則Sec-WebSocket-Protocol-Client描述了客戶端到服務(wù)器發(fā)送的|Sec-WebSocket-Protocol|頭字段值的語法。
以下新的頭字段可以在從客戶端到服務(wù)器握手期間被發(fā)送:
Sec-WebSocket-Key = base64-value-non-empty
Sec-WebSocket-Extensions = extension-list
Sec-WebSocket-Protocol-Client = 1#token
Sec-WebSocket-Version-Client = version
base64-value-non-empty = (1*base64-data [ base64-padding ]) |
base64-padding
base64-data = 4base64-character
base64-padding = (2base64-character "==") |
(3base64-character "=")
base64-character = ALPHA | DIGIT | "+" | "/"
extension-list = 1#extension
extension = extension-token *( ";" extension-param )
extension-token = registered-token
registered-token = token
extension-param = token [ "=" (token | quoted-string) ]
; When using the quoted-string syntax variant, the value
; after quoted-string unescaping MUST conform to the
; 'token' ABNF.
NZDIGIT = "1" | "2" | "3" | "4" | "5" | "6" |
"7" | "8" | "9"
version = DIGIT | (NZDIGIT DIGIT) |
("1" DIGIT DIGIT) | ("2" DIGIT DIGIT)
; Limited to 0-255 range, with no leading zeros
以下新的頭字段可以在服務(wù)器到客戶端握手期間被發(fā)送:
Sec-WebSocket-Extensions = extension-list
Sec-WebSocket-Accept = base64-value-non-empty
Sec-WebSocket-Protocol-Server = token
Sec-WebSocket-Version-Server = 1#version
本節(jié)提供了在客戶端和服務(wù)器中支持多個(gè)版本的WebSocket協(xié)議的一些指導(dǎo)。
使用WebSocket版本通知能力(|Sec-WebSocket-Version|頭字段),客戶端可以初始請(qǐng)求它選擇的WebSocket協(xié)議的版本(這并不一定必須是客戶端支持的最新的)。如果服務(wù)器支持請(qǐng)求的版本且握手消息是本來有效的,服務(wù)器將接受該版本。如果服務(wù)器不支持請(qǐng)求的版本,它必須以一個(gè)包含所有它將使用的版本的|Sec-WebSocket-Version|頭字段(或多個(gè)|Sec-WebSocket-Version|頭字段)來響應(yīng)。此時(shí),如果客戶端支持一個(gè)通知的版本,它可以使用新的版本值重做WebSocket握手。
以下示例演示了上述的版本協(xié)商。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
...
Sec-WebSocket-Version: 25
服務(wù)器的響應(yīng)可能看起來像如下:
HTTP/1.1 400 Bad Request
...
Sec-WebSocket-Version: 13, 8, 7
注意服務(wù)器最后的響應(yīng)可能也看起來像:
HTTP/1.1 400 Bad Request
...
Sec-WebSocket-Version: 13
Sec-WebSocket-Version: 8, 7
客戶端現(xiàn)在可以重做符合版本13的握手:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
...
Sec-WebSocket-Version: 13
更多建議: