(二) HTTP/2起步

與HTTP1.x一樣,HTTP/2仍然是建立在TCP連接之上的應用層協議,請求由客戶端發起,並且,URI的基本規則保持不變。

HTTP/2的版本標識

對應URI中的http或https,HTTP/2有2個版本標識:

  • “h2”對應以”https”開頭的URI,表示HTTP/2是運行在TLS之上的,由TLS提供認證和加密等安全保障;
  • “h2c”對應以”http”開頭的URI,表示HTTP/2是運行在明文TCP之上的。

HTTP1.1連接“升級”到HTTP/2

如果客戶端無法確定服務端是否支持HTTP/2,那麼,客戶端需要利用HTTP1.1的“升級”機制來發起請求。在請求報文中需要包含一個Upgrade報頭字段,除此之外,必須包含一個HTTP2-Settings報頭字段。例如:

GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>

包含有效載荷主體的請求必須在客戶端能夠發送HTTP/2的幀之前全部發送出去,這意味着一個較大的請求會阻塞TCP連接的使用,直到全部內容發送完畢。

如果多個請求的併發是重要的,也就是說,希望最大限度地做到多個請求的併發,那麼,可以利用HTTP1.1的OPTIONS請求作爲初始請求來“升級”到HTTP/2。原因是OPTIONS請求的體積較小,它阻塞TCP連接的時間也就較短,後續的各個請求就可以併發發送了。代價是額外耗費了一個OPTIONS請求的往返成本。

不支持HTTP/2的服務端會直接忽略Upgrade頭域,返回一個HTTP1.1的200響應,例如:

HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html

...

如果Upgrade的值不是”h2c”而是”h2”,那麼,服務端也會直接忽略掉它。

支持HTTP/2的服務端會接受“升級”並返回一個HTTP1.1的101響應。在終止101響應的空行之後,服務端就可以發送HTTP/2的幀了。這些幀必須包含對發起“升級”請求的響應。例如:

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c

[ HTTP/2 connection ...

服務端發送的第一個HTTP/2幀必須是一個包含SETTINGS幀 的服務端連接序言。客戶端在收到101響應後必須也發送一個包含SETTINGS幀的連接序言。

客戶端在“升級”成功之前發送的HTTP1.1請求會被分配一個值爲1的“流”標識,並被賦予默認的優先級。

前面提到,一個請求從HTTP1.1升級到HTTP/2,必須顯式地包含HTTP2-Settings報頭字段。HTTP2-Settings是一個連接相關的報頭字段,包含管理HTTP/2連接的參數,期待着服務端會接受升級請求。
如果請求中沒有HTTP2-Settings或者有多個HTTP2-Settings,服務端都會拒絕升級。另外,服務端不能發送HTTP2-Settings報頭。HTTP2-Settings報頭的內容是SETTINGS幀的有效載荷,使用base64url編碼。

因爲升級只是意欲應用在當前的連接,所以客戶端除了發送HTTP2-Settings報頭外,還必須將”HTTP2-Settings”作爲一個連接選項放到Connection報頭中,以達到阻止轉發到下一跳的目的。(這裏的一跳指的是HTTP連接的一跳,而非IP路由的一跳)

開始一個HTTP/2的https請求

客戶端通過使用TLS的應用層協議協商擴展(TLS-ALPN)來發起請求。

在TLS之上的HTTP/2使用”h2”標識,而不能使用”h2c”標識。

一旦TLS協商完成,客戶端和服務端都必須發送一個連接序言。

預先知道的情況下開始HTTP/2請求

客戶端可以通過其它方式判斷某個服務端是否支持HTTP/2。例如,ALT-SVC描述了一種公告這種能力的機制。

對於支持HTTP/2的服務端,客戶端必須發送連接序言,然後可以立即發送HTTP/2的幀。服務端可以通過連接序言識別這些連接。這隻影響基於明文TCP的HTTP/2連接的建立;基於TLS的HTTP/2實現必須使用TLS的協議協商(TLS-ALPN)。類似地,服務端也必須發送一個連接序言。

在沒有更多信息的情況下,先前對HTTP/2的支持並不表明一個服務端在以後的連接中一定支持HTTP/2。例如,服務器的配置可能會改變,或者一個集羣中不同服務器的配置可能有差異,或者隨網絡條件而變化。

HTTP/2連接序言

在HTTP/2中,每個端點都被要求發送一個連接序言,其作用是:

  • 作爲正在使用的協議的最終確認;
  • 爲HTTP/2連接建立初始設置。

客戶端和服務端各自發送一個不同的連接序言。

客戶端的連接序言以一個24字節的序列開始,其十六進制表示是:

0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a

其字符串表示是:

PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n)

這個序列之後必須是一個SETTINGS幀(可以是空幀)。客戶端在收到101響應後立即發送客戶端連接序言,或者將連接序言作爲TLS連接的第一組應用數據字節。如果在預先知道服務端支持HTTP/2的情況下發起HTTP/2連接,客戶端連接序言在連接建立後發送。

客戶端連接序言是被特意選擇的,目的是使大部分服務端和中間代理不嘗試進一步處理其後的幀。

服務端連接序言包含一個有可能爲空的SETTINGS幀,它必須是服務端在HTTP/2上發送的第一個幀。

作爲連接序言的一部分,來自對端的SETTINGS幀必須在發送本端連接序言之後加以確認。

爲了避免不必要的延遲,允許客戶端在發送客戶端連接序言之後立即發送額外的幀,不需要等待接收服務端的連接序言。然而,需要注意的是,服務端連接序言的SETTINGS幀中可能包含期望客戶端如何與服務端通信的必要參數修改。在接收到SETTINGS幀之後,客戶端應該尊敬建立的全部參數。在一些配置中,服務端可以在客戶端發送額外的幀之前傳送SETTINGS幀,從而提供了一個避免這種問題的機會。

客戶端和服務端都必須將無效的連接序言視爲一種類型是PROTOCOL_ERROR的連接錯誤,在這種情況下,可以發送一個GOAWAY幀,因爲一個無效的連接序言表明對端沒有使用HTTP/2協議。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章