?
This document uses PHP Chinese website manual Release
在HTTP協(xié)議提供了一個(gè)特殊機(jī)制,使已建立的連接升級(jí)到一個(gè)新的,不兼容,協(xié)議。本指南介紹了它的工作原理,并提供了其使用場(chǎng)景的示例。
此機(jī)制始終由客戶端啟動(dòng)(有一個(gè)例外:服務(wù)器可能需要升級(jí)到TLS),并且服務(wù)器可能接受或拒絕切換到新協(xié)議。這使得使用常用協(xié)議(如HTTP / 1.1)啟動(dòng)連接成為可能,然后請(qǐng)求連接切換到HTTP / 2或甚至到WebSocket。
協(xié)議升級(jí)總是由客戶請(qǐng)求; 沒(méi)有為服務(wù)器提供請(qǐng)求協(xié)議更改的機(jī)制。當(dāng)客戶機(jī)希望升級(jí)到新的協(xié)議,它通過(guò)發(fā)送任何類型的正常請(qǐng)求發(fā)送到服務(wù)器(這樣做GET
,POST
等)。但是,該請(qǐng)求需要專門配置以包含升級(jí)請(qǐng)求。
特別是,請(qǐng)求需要這兩個(gè)額外的頭文件:
Connection: Upgrade
該Connection
頭被設(shè)置為"Upgrade"
以表示的升級(jí)要求。Upgrade:
protocols
所述Upgrade
標(biāo)頭指定的一個(gè)或多個(gè)以逗號(hào)分隔的協(xié)議名稱,首選項(xiàng)的順序。
根據(jù)請(qǐng)求的協(xié)議,可能需要其他頭文件; 例如,WebSocket升級(jí)允許額外的頭部配置關(guān)于WebSocket連接的細(xì)節(jié),并在打開(kāi)連接時(shí)提供一定程度的安全性。有關(guān)更多詳細(xì)信息,請(qǐng)參閱升級(jí)到WebSocket連接。
服務(wù)器可拒絕升級(jí)-在這種情況下,它僅僅是忽略了"Upgrade"
頭并發(fā)送回一個(gè)普通的響應(yīng)("200 OK"
如果它可以提供所請(qǐng)求的資源時(shí),30x
如果它要執(zhí)行重定向,狀態(tài)碼40x
或50x
一個(gè)如果不能提供請(qǐng)求的資源) - 或接受升級(jí)。在這種情況下,它會(huì)發(fā)送一個(gè)"101 Switching Protocols"
帶有升級(jí)標(biāo)頭的指定所選協(xié)議的標(biāo)頭。
在發(fā)送101
狀態(tài)碼之后,如果新協(xié)議要求它發(fā)生新的協(xié)議的最終握手,則服務(wù)器"Upgrade"
按照新的協(xié)議規(guī)則發(fā)送原始請(qǐng)求(包括標(biāo)頭的請(qǐng)求)所請(qǐng)求的答案。
的101
狀態(tài)代碼被發(fā)送作為對(duì)包括一個(gè)請(qǐng)求的響應(yīng)"Upgrade"
報(bào)頭以信號(hào)通知請(qǐng)求的接收方愿意升級(jí)到所期望的協(xié)議之一。如果"101 Switching Protocols"
狀態(tài)碼被返回,則標(biāo)題還必須包含描述所選協(xié)議的標(biāo)題Connection
和Upgrade
標(biāo)題。請(qǐng)參閱此機(jī)制的常見(jiàn)用法中的示例,以了解有關(guān)這種機(jī)制的更多信息。
雖然您可以使用協(xié)議升級(jí)機(jī)制將HTTP / 1.1連接升級(jí)到HTTP / 2,但您不能以其他方式。實(shí)際上,HTTP / 2不再支持101狀態(tài)碼,因?yàn)镠TTP / 2沒(méi)有升級(jí)機(jī)制。
這里我們看一下Upgrade
頭部最常見(jiàn)的用例。
由于其廣泛的支持,使用HTTP / 1.1啟動(dòng)連接的標(biāo)準(zhǔn)過(guò)程是,然后請(qǐng)求升級(jí)到HTTP / 2。這樣,即使服務(wù)器不支持HTTP / 2,仍然可以正常工作。但是,只能升級(jí)到不安全(明文)HTTP / 2連接。這是通過(guò)使用目標(biāo)協(xié)議名稱來(lái)完成的h2c
,該名稱代表“HTTP / 2 Cleartext”。這也需要指定HTTP2-Settings
標(biāo)題字段。
GET / HTTP/1.1Host: destination.server.ext Connection: Upgrade, HTTP2-Settings Upgrade: h2c HTTP2-Settings: base64EncodedSettings
這里base64EncodedSettings
是一個(gè)HTTP / 2 "SETTINGS"
幀的有效載荷,它已經(jīng)被base64url編碼,所有的尾隨"="
(等于)字符被刪除,以便將其安全地包含在這個(gè)文本標(biāo)題格式中。
所述base64url格式是不一樣的標(biāo)準(zhǔn)Base64編碼。這與標(biāo)準(zhǔn)的Base64差不多,但不完全相同。唯一的區(qū)別:為了確保所得到的字符串是在URL和文件名使用安全的字母表中的第62和第63個(gè)字符從改變"+"
和"/"
到"-"
(負(fù))和"_"
(下劃線),分別。
如果服務(wù)器由于某種原因無(wú)法切換到HTTP / 2,那么在正常處理請(qǐng)求后,它將回復(fù)標(biāo)準(zhǔn)的HTTP / 1回復(fù)。因此,如果請(qǐng)求是獲取事實(shí)上存在的網(wǎng)頁(yè),那么您將"HTTP/1.1 200 OK"
在網(wǎng)頁(yè)的其余部分之后獲得標(biāo)準(zhǔn)響應(yīng)。如果服務(wù)器能夠切換到HTTP / 2,HTTP/1.1 101 Switching Protocols"
則會(huì)發(fā)送一個(gè)“ 響應(yīng)” ,如下所示:
HTTP/1.1 101 Switching Protocols Connection: Upgrade Upgrade: h2c[standard HTTP/2 server connection preface, etc.]
在HTTP / 1.1頭部和指示頭部結(jié)尾的空白行之后,服務(wù)器將立即包含服務(wù)器連接前言,從一個(gè)SETTINGS
幀開(kāi)始。
到目前為止,升級(jí)HTTP連接最常見(jiàn)的用例是使用WebSocket,它通常通過(guò)升級(jí)HTTP或HTTPS連接來(lái)實(shí)現(xiàn)。請(qǐng)記住,如果您使用WebSocket API或任何執(zhí)行WebSocket的庫(kù)打開(kāi)新連接,則大部分或所有這些都是為您完成的。例如,打開(kāi)WebSocket連接非常簡(jiǎn)單:
webSocket = new WebSocket("ws://destination.server.ext", "optionalProtocol");
該WebSocket()
構(gòu)造函數(shù)創(chuàng)建一個(gè)初始的HTTP / 1.1連接,然后處理握手和升級(jí)過(guò)程中的所有工作。
您也可以使用"wss://"
URL方案打開(kāi)安全的WebSocket連接。
如果您需要從頭開(kāi)始創(chuàng)建WebSocket連接,則必須自己處理握手過(guò)程。在創(chuàng)建初始HTTP / 1.1會(huì)話之后,您需要通過(guò)添加標(biāo)準(zhǔn)請(qǐng)求Upgrade
和Connection
頭部來(lái)請(qǐng)求升級(jí),如下所示:
Connection: Upgrade Upgrade: websocket
WebSocket升級(jí)過(guò)程涉及以下頭文件。除了頭文件Upgrade
和Connection
頭文件,其余的文件通常都是可選的,或者在瀏覽器和服務(wù)器互相通話時(shí)為您處理。
Sec-WebSocket-Extensions
指定要求服務(wù)器使用的一個(gè)或多個(gè)協(xié)議級(jí)WebSocket擴(kuò)展。Sec-WebSocket-Extension
允許在請(qǐng)求中使用多個(gè)頭部; 結(jié)果與您在一個(gè)這樣的標(biāo)題中包含所有列出的擴(kuò)展名相同。
Sec-WebSocket-Extensions: extensions
extensions
用逗號(hào)分隔的請(qǐng)求(或同意支持)的擴(kuò)展名列表。這些應(yīng)該從IANA WebSocket擴(kuò)展名注冊(cè)表中選擇。帶參數(shù)的擴(kuò)展使用分號(hào)描述。
例如:
Sec-WebSocket-Extensions: superspeed, colormode; depth=16
Sec-WebSocket-Key
向服務(wù)器提供信息,以確認(rèn)客戶端有權(quán)請(qǐng)求升級(jí)到WebSocket。當(dāng)不安全(HTTP)客戶希望升級(jí)時(shí),可以使用此頭文件,以提供一定程度的防范濫用保護(hù)。使用WebSocket規(guī)范中定義的算法計(jì)算密鑰的值,因此不提供安全性。相反,它有助于防止非WebSocket客戶端無(wú)意中或通過(guò)濫用請(qǐng)求WebSocket連接。從本質(zhì)上說(shuō),這個(gè)關(guān)鍵只是確認(rèn)“是的,我真的打算打開(kāi)一個(gè)WebSocket連接?!?/p>
這個(gè)標(biāo)題是由選擇使用它的客戶端自動(dòng)添加的; 它不能使用該XMLHttpRequest.setRequestHeader()
方法添加。
Sec-WebSocket-Key: key
key
此請(qǐng)求升級(jí)的關(guān)鍵。如果客戶希望這樣做,則客戶端會(huì)添加該服務(wù)器,并且服務(wù)器會(huì)在響應(yīng)中包含自己的密鑰,客戶端會(huì)在向您提供升級(jí)響應(yīng)之前驗(yàn)證該密鑰。
服務(wù)器的響應(yīng)Sec-WebSocket-Accept
頭將有一個(gè)基于指定的值計(jì)算出來(lái)的值key
。
Sec-WebSocket-Protocol
該Sec-WebSocket-Protocol
頭指定要使用,按優(yōu)先順序的一個(gè)或多個(gè)的WebSocket協(xié)議。服務(wù)器支持的第一個(gè)服務(wù)器將被選中,并由服務(wù)器在Sec-WebSocket-Protocol
響應(yīng)中包含的標(biāo)題中返回。您也可以在標(biāo)題中多次使用它,結(jié)果與在單個(gè)頭中使用逗號(hào)分隔的子協(xié)議標(biāo)識(shí)符列表相同。
Sec-WebSocket-Protocol: subprotocols
subprotocols
按照優(yōu)先順序,按逗號(hào)分隔的子協(xié)議名稱列表。子協(xié)議可以從IANA WebSocket子協(xié)議名稱注冊(cè)中選擇,也可以是客戶和服務(wù)器共同理解的定制名稱。
Sec-WebSocket-Version
指定客戶端希望使用的WebSocket協(xié)議版本,以便服務(wù)器可以確認(rèn)該版本是否受支持。
Sec-WebSocket-Version: version
version
客戶端希望在與服務(wù)器通信時(shí)使用的WebSocket協(xié)議版本。此號(hào)碼應(yīng)為IANA WebSocket版本號(hào)注冊(cè)表中列出的最新版本。WebSocket協(xié)議的最新最終版本是版本13。
如果服務(wù)器無(wú)法使用指定版本的WebSocket協(xié)議進(jìn)行通信,它將響應(yīng)一個(gè)錯(cuò)誤(如需要升級(jí)426),在其標(biāo)題中包含一個(gè)包含Sec-WebSocket-Version
受支持協(xié)議版本的逗號(hào)分隔列表的標(biāo)題。如果服務(wù)器確實(shí)支持所請(qǐng)求的協(xié)議版本,Sec-WebSocket-Version
則響應(yīng)中不會(huì)包含標(biāo)題。
Sec-WebSocket-Version: supportedVersions
supportedVersions
服務(wù)器支持的WebSocket協(xié)議版本的逗號(hào)分隔列表。
服務(wù)器的響應(yīng)可能包括這些。
Sec-WebSocket-Accept
在服務(wù)器愿意啟動(dòng)WebSocket連接時(shí),在打開(kāi)握手過(guò)程期間包含在服務(wù)器的響應(yīng)消息中。它在repsonse頭文件中只會(huì)出現(xiàn)一次。
Sec-WebSocket-Accept: hash
hash
如果Sec-WebSocket-Key
提供了頭文件,則通過(guò)獲取該密鑰的值來(lái)計(jì)算此頭文件的值,并將字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”連接到該字符串,并取該連接字符串的SHA-1散列值,結(jié)果在一個(gè)20字節(jié)的值。然后該值被base64編碼以獲得該屬性的值。
您也可以將HTTP / 1.1連接升級(jí)到TLS / 1.0。這樣做的主要優(yōu)點(diǎn)是可以避免在服務(wù)器上使用從“http://”到“https://”的URL重定向,并且可以在虛擬主機(jī)上輕松使用TLS。但是,這可能會(huì)導(dǎo)致代理服務(wù)器出現(xiàn)問(wèn)題。
升級(jí)HTTP連接以使用TLS將Upgrade
標(biāo)記與標(biāo)記一起使用"TLS/1.0"
。如果交換機(jī)成功完成,原始請(qǐng)求(包括其中Upgrade
)將按照正常完成,但在TLS連接上完成。
對(duì)TLS的請(qǐng)求可以選擇性地或強(qiáng)制性地進(jìn)行。
要升級(jí)到TLS(也就是說(shuō),如果升級(jí)到TLS失敗,允許連接繼續(xù)以明文方式),只需按預(yù)期方式使用Upgrade
和Connection
標(biāo)題。例如,給出原始請(qǐng)求:
GET http://destination.server.ext/secretpage.html HTTP/1.1Host: destination.server.ext Upgrade: TLS/1.0Connection: Upgrade
如果服務(wù)器不支持TLS升級(jí),或者無(wú)法在當(dāng)時(shí)升級(jí)到TLS,則它會(huì)使用標(biāo)準(zhǔn)的HTTP / 1.1響應(yīng)進(jìn)行響應(yīng),例如:
HTTP/1.1 200 OK Date: Thu, 17 Aug 2017 21:07:44 GMT Server: Apache Last-Modified: Thu, 17 Aug 2017 08:30:15 GMT Content-Type: text/html; charset=utf-8Content-Length: 31374<html> ...</html>
如果服務(wù)器確實(shí)支持TLS升級(jí)并希望允許升級(jí),它將使用"101 Switching Protocols"
響應(yīng)代碼進(jìn)行響應(yīng),如下所示:
HTTP/1.1 101 Switching Protocols Upgrade: TLS/1.0, HTTP/1.1
一旦TLS握手完成,原始請(qǐng)求將被正常響應(yīng)。
要請(qǐng)求強(qiáng)制升級(jí)到TLS(即升級(jí)失敗并在升級(jí)失敗時(shí)連接失?。牡谝粋€(gè)請(qǐng)求必須是一個(gè)OPTIONS
請(qǐng)求,如下所示:
OPTIONS * HTTP/1.1Host: destination.server.ext Upgrade: TLS/1.0Connection: Upgrade
如果升級(jí)到TLS成功,服務(wù)器將"101 Switching Protocols"
按照上一節(jié)所述進(jìn)行響應(yīng)。如果升級(jí)失敗,HTTP / 1.1連接將失敗。
這與客戶端啟動(dòng)的升級(jí)大致相同,通過(guò)將Upgrade
頭添加到任何消息來(lái)請(qǐng)求可選的升級(jí)。然而,強(qiáng)制升級(jí)的工作方式稍有不同,因?yàn)樗鼤?huì)通過(guò)回復(fù)收到的帶有426
狀態(tài)碼的消息來(lái)請(qǐng)求升級(jí),如下所示:
HTTP/1.1 426 Upgrade Required Upgrade: TLS/1.1, HTTP/1.1Connection: Upgrade<html>... Human-readable HTML page describing why the upgrade is required and what to do if this text is seen ...</html>
如果接收到"426 Upgrade Required"
響應(yīng)的客戶端愿意且能夠升級(jí)到TLS,則應(yīng)該啟動(dòng)上面在客戶端啟動(dòng)的升級(jí)到TLS的過(guò)程中所述的相同過(guò)程。
WebSocket API
HTTP
規(guī)格和RFC:
RFC 2616
RFC 6455
RFC 2817
RFC 7540
在MDN上編輯此頁(yè)面