1. 程式人生 > 其它 >Go 標準庫 HTTP2 協議升級細節

Go 標準庫 HTTP2 協議升級細節

客戶端行為

首次呼叫 Transport.RoundTrip()

  1. 初始化 Transport 的 TLS ALPN 列表,加入 "h2" ALPN (code)。同時設定 "h2" ALPN 對應的協議升級函式 (code)。

  2. 建立TCP連線,隨即啟動TLS握手流程 (code)。客戶端傳送給服務端的 TLS 握手訊息,會攜帶步驟1中設定的 "h2" ALPN (code),與服務端協商。

  3. 服務端接受 "h2" ALPN,同樣在握手訊息中攜帶 "h2" 作為 ALPN 協商的結果,響應給客戶端。客戶端快取此結果 (code)。

  4. 客戶端根據 ALPN 協商結果——"h2",找回步驟1中設定的協議升級函式,通過此函式生成新的 HTTP2 Transport ,將其儲存到連線的 alt

    變數中 (code)。

  5. 因為 HTTP2 連線可以同時被多個請求複用(通過 HTTP2 Stream),沒有被佔用的問題,直接把它當成是“空閒”連線,放入到連線池中(code)。

  6. 由於連線的 alt 變數(HTTP2 Transport )不為空,客戶端直接使用此 Transport 傳送 http 請求,繞過了 HTTP1 相關的處理 (code)。

  7. HTTP2 Transport 建立一個新的 Stream 傳送請求 (code)。

後續呼叫 Transport.RoundTrip()

  1. 客戶端在連線池中發現“空閒”狀態的 HTTP2 連線,因為 HTTP2 連線可以同時被多個請求複用(通過 HTTP2 Stream),沒有被佔用的問題。直接使用這個連線,而且無需將它從連線池中移除(仍舊保持“空閒”狀態)。

  2. 由於連線的 alt 變數(HTTP2 Transport )不為空,客戶端直接使用此 Transport 傳送 http 請求,繞過了 HTTP1 相關的處理 (code)。

  3. HTTP2 Transport 建立一個新的 Stream 傳送請求 (code)。

服務端處理

  1. 服務端啟動時,會初始化所支援的 TLS ALPN 列表,加入 "h2" ALPN (code)。同時設定 "h2" ALPN 對應的協議升級函式 (code)。
  2. 接受TCP連線,開始TLS握手流程(code)。不出意外,客戶端會在 TLS 握手訊息中提供 "h2" ALPN,服務端根據步驟1提供的所支援的 TLS ALPN 列表,最終 "h2" 會被選擇為協商的結果。服務端快取此結果(
    code
    )。
  3. 服務端基於 ALPN 協商結果——"h2",找回步驟1中設定的協議升級函式,直接通過此函式處理 HTTP 請求,繞過了 HTTP1 相關的處理 (code)。
  4. 處理 HTTP2 Stream (code)。

結論

  • Go 標準庫通過 TLS (HTTPS) 的 ALPN 協商 直接識別處理 HTTP2 流量,沒有走常規 HTTP1 升級 HTTP2 的流程,縮短了連線建立的時間,效能更好。
  • Transport 連線池託管 HTTP2 連線的意義不大,對於同一個域名,連線池內通常只有一個 HTTP2 連線,通過在 HTTP2 連線內 建立多個 Stream 來複用連線。