博客 / 詳情

返回

HTTP學習筆記(三) HTTP/2

這裏簡單的介紹一下HTTP 2.0。

由HTTP 1.1 走向 HTTP 2.0

寫這篇文章的時候我在聽B站UP主翻唱的歌曲,然後我心血來潮打算看看B站現在用的是HTTP的哪個版本,於是我摁下了F12鍵。

B站使用的網絡協議版本

這個h2和h3代表的是HTTP 2.0 和3.0? 這版本號刷的這麼快的嗎? 不應該是2.1==>2.5 ==>3.0這樣嗎?為了驗證我的想法,我打開了火狐瀏覽器。

火狐瀏覽器

所以就很突然,本來按照計劃只介紹HTTP/2.0的,然後HTTP/3.0也只得加入到學習計劃中,所以每次學習一個知識點的時候,總會碰到新的,生也有涯,知也無涯的感覺,在前面兩篇文章了,我們已經大致的介紹HTTP 0.9 、1.0、1.1。

2.0 與1.1的不同

1.1 的新特性

我們這裏來再度介紹一下HTTP 1.1帶來的改進:

  • 連接可以複用,節省了多次打開 TCP 連接加載網頁文檔資源的時間。

HTTP 1.1 之前的連接模型使短連接,也是HTTP/1.0是短連接,每一個HTTP請求都由它自己獨立的連接完成;這意味着發起每一個HTTP請求之前都會有一次TCP握手。 TCP協議本身握手本身就是耗費時間的,所以TCP可以保持更多的熱連接來適應負載。

火狐開發者文檔是如是吐槽這個模型的: 除非是要兼容一個非常古老的,不支持長連接的系統,沒有一個令人信服的理由繼續使用這個模型。為了緩解這些問題,長連接的概念便被設計出來了,甚至在HTTP/1.1之前。或者這被稱為一個keep-alive連接。

一個長連接會保持一段時間,重複用於發送一系列請求,節省了新建TCP連接握手的時間,還可以利用TCP性能增強能力。當然這個連接也不會一直保留着: 連接在空閒一段時間後會被關閉(服務器可以使用Keep-Alive協議頭來指定一個最小的連接保持時間)

但是長連接也不是完美無缺的;就算是在空閒狀態,它還是會消耗服務器資源,而且在重負載時,還有可能遭受Dos attacks攻擊。在這種場景下,可以使用非長連接,既儘快關閉那些空閒的連接,也能對性能有所提升。

  • 增加管線化技術,允許在第一個應答被完全發送之前就發送第二個請求,以降低通信延遲。

管線化的英文是pipelining,pipelining還有另一個意思是流水線。我看火狐開發者文檔的時候,中文版將pipelining在介紹HTTP的演變為翻譯為管線化,但是在介紹連接管理的時候,由將其譯為流水線。我剛看的時候還以為是兩種技術,事實上是一個名詞的翻譯。

但是火狐的開發者文檔評價管線化技術,比較難用,現代瀏覽器默認不會啓用此特性。這個特性被更好的算法所代替,也就是HTTP/2

  • 支持響應分塊。

簡單的説這個代表分塊傳輸,通常情況下,HTTP應答消息中發送的數據是整個發送的,Content-Length消息頭部表示數據的長度,客户端需要直到那裏是應答消息的結束,以及後續應答消息的開始。一個比較常見的應用是斷點續傳,實現H5頁面的大視頻播放,實現漸進式播放,不需要將整個文件加載到內存中。

值得注意的是此特性在HTTP/2.0中並不支持,HTTP/2.0提供了一種更加有效率的數據流方式。

  • 引入額外的緩存控制機制。
簡單的説就是引入了Cache-Control, 用Cache-control區分了緩存的類型,制定了緩存過期策略。
  • 引入內容協商機制,包括語言,編碼,類型等,並允許客户端和服務器之間約定以最合適的內容進行交換。
  • 憑藉Host頭, 能夠使不同域名配置在同一個ip地址的服務器上。

HOST頭

有的同學看到這裏會問,眾所周知,HTTP用的是TCP協議,發送HTTP請求的時候,IP地址和端口必然是已知的,那麼HOST的意義在哪裏呢?舉一個實際的例子是,Tomcat中部署多個服務,事實上一個Tomcat可以對應多個服務,現在是Spring Boot時代,Tomcat已經默認集成在裏面,是一個應用對一個Tomcat。如果你開發過Servlet,還沒到Spring Boot,那個時候是打war包的,war被放在webapps下面,我們在Tomcat中可以配置Host頭,Tomcat會根據不同的host頭轉發到對應的服務上。打開Tomcat的server.xml:

Server.xml

### 流水線(pipelining)的設計問題

上面我們提到了HTTP 1.1引入了流水線,允許第一個響應被完全返回前,客户端發送第二個請求,我認為這是合理的設計,但是為什麼現代瀏覽器大多沒啓用此特性嗎?

I would always recommend going to the authoritative source when trying to understand the meaning and purpose of HTTP headers.

如果你在嘗試理解HTTP頭的含義和用頭時,我總是建議你去原始權威文檔.

上面這句話出自StackOverflow中What is HTTP "Host" header?的答案下,我挺喜歡這句話的。其實這個答案我在StackOverFlow上已經看到了答案,有同學可能會問,百度找不到嗎?説句慚愧的話,找的到,但是比較費勁,Stackoverflow這種問答式網站找起問題來更快。

答案是: 流水線要求響應按請求順序返回。

流水線

這種設計會帶來隊頭阻塞問題(Head of line Blocking), 只要第一個HTTP流遭遇到阻塞,那麼第二個響應就得一直排隊等待。那為什麼你要按順序返回呢?

答案是: Because there is no identifier in the response indicating to which request it belongs.

響應沒有標識符區別響應式屬於哪一個請求的。

那麼請問HTTP/2.0是如何解決這個問題的?

HTTP/2 solves this with stream identifiers.

HTTP / 2使用流標識符來解決了這個問題。

為了更快的速度-來吧HTTP/2

HTTP/2 的改進

HTTP/2是有官網的, 我們可以在官網看到對HTTP/2的認知

  • is binary, instead of textual
傳輸的是二進制數據,不再是文本。
  • is fully multiplexed, instead of ordered and blocking
多路複用取代了順序和阻塞。
  • can therefore use one connection for parallelism
可以並行請求
  • uses header compression to reduce overhead
壓縮請求減少消耗
  • allows servers to “push” responses proactively into client caches
其允許服務器在客户端緩存中填充數據,通過一個叫服務器推送的機制來提前請求。

is fully multiplexed 多路複用與並行請求

我們舉一個小例子來説明HTTP 1.0 ==> HTTP1.1 ==> HTTP/2的變化, 為了説明這個變化,我們需要請出網購達人小明。

如果小明需要在一個淘寶店網購多個東西,在HTTP 1.0下, 不能放在一個訂單裏面(一個TCP連接裏面),只能是一個商品一個訂單。

這也太浪費時間了吧,於是小明切換到了HTTP/1.1, 雖然不用開多個訂單,但其實限制也比較大,也還是隻能一次訂購一個,雖然最後都被算在了一個訂單中(一個TCP連接)。於是小明切換到了HTTP/1.1的流水線模式,在一個訂單裏買了10件商品,但是他們會按照請求順序依次到達,如果某件商品缺貨或者遺失,那麼小明必須等待這件商品到貨或者補發到貨之後,才能收到下一個商品。這也太複雜了吧。

小明馬上切換到了HTTP/2模式,在這個模式下,小明可以按照任意順序購買商品,哪個商品準備好了,哪個商品就率先發貨,所以他們的到達順序和你的購買順序可能是不一樣的,為了加速,商家還可能拆分商品。這也就是HTTP/2的多路複用,一個連接上多個請求,不再像HTTP/1.1要求的那樣,要求響應按請求順序返回。

上面這個絕妙的比喻來於StackOverFlow下What does multiplexing mean in HTTP/2這個問題的回答,這個結果頗為簡單易懂。

is binary, instead of textual 二進制的而不是文本的

上面的話也就是在説,HTTP/2之前使用的是文本的,但是最終傳輸的不都是二進制的嗎? 我們可以説二進制是令人困惑的術語,因為數據在計算機中最後都是二進制形式的。所以有什麼區別呢?

為了解決我的問題,我決定使用Wireshark進行抓包,對比HTTP/1.1和HTTP/2的區別。但是我忽略了一點,目前基本上使用HTTP/2網站都是HTTPS,然後我在抓包工具中看到的就是TLS V 1.2這樣的東西,這些都是密文。所以我又想用Spring Boot做一個支持HTTP/2的後台,然後自己抓包分析一下,然後發現Spring Boot 不支持HTTP/2的明文版本, 原來HTTP/2分成兩個版本,一個是明文版,一個是基於加密的。但是目前瀏覽器和Spring Boot 只支持基於加密的版本,所以必須有加密證書,如果你禁用加密,通過瀏覽器進行訪問的時候,瀏覽器會進行自動降級,將HTTP/2降級為HTTP/1.1。

所以通過自己搭建支持HTTP/2網站的想法報銷了,因為比較麻煩。我只能將希望轉到有支持HTTP/2明文的網站, 於是我找到了下面這篇文章:

  • HTTP/2 協議抓包實戰 https://zhuanlan.zhihu.com/p/...

裏面給了一個HTTP/2的明文網站,遺憾的是在我去抓的時候,人家升級成HTTP/2密文了,同樣的curl命令,他抓到請求中有請求升級協議的,我這裏沒抓到,我進到網站一看,發現人家已經是HTTPS了。所以思來想去,可能我們提出的問題本身就是由問題的,我們的問題是最終傳輸的時候都是二進制,所以提出的問題是有什麼區別?我想下面的回答可以局部回答我們的問題:

The first is that some people have suggested that the bottom layer of the HTTP protocol is still 0 and 1. How can it be a text protocol? The answer is whether a protocol is a text protocol or not, it has nothing to do with the upper and lower layers of the network model, but only with itself.

有人認為HTTP協議的底層仍然是0和1,那為什麼HTTP就算是文本協議了呢? 答案是一個協議是基於文本還是其他,不在於他的上層還是下層,僅僅在於它本身。

那你還是沒回答HTTP/1.1交付給傳輸層的數據和HTTP/2交付給傳輸層的有什麼區別啊? 我想大概就是在編碼和格式上了。這裏簡單的介紹一下文本編碼和二進制編碼的區別,他們都是表示數據的形式。對於數字來説,一個數字比如説用二進制協議,比如98765,這是個五位數,兩個字節不大夠,我們大致要上三個字節來表示。那如果用文本協議呢,那就是一個字符一個字節,五個數字也就是五個字節。這就節省了兩個字節。第二個就是固定了格式,將原來的Header+Body變為數個分散的幀:

報文演變

為什麼是HTTP/2而不是HTTP 1.2

最初的HTTP/2被稱為HTTP/2.0,HTTP/2工作組給出瞭解釋,他們認為以前的1.0,1.1造成了很多換亂和誤解,讓人在實際的使用難以區分差異,所以將這次的版本號定位HTTP/2,棄用次要版本號“.0”。

Java 領域對HTTP/2的支持

雖然現在HTTP/3已經出來了,但是Java領域對此支持的HTTP Client,就我熟悉的而言,還處於積極的適配HTTP/2中,Maven 倉庫中的Apache HttpClient最新版本還處於4.5.2,這個目前還只是支持HTTP1.1版本。

寫在最後

本篇的定位是簡介,簡單介紹了HTTP/2的主要特性,本身是想做抓包的,但是抓包的相關的解析又會加大大本篇的篇幅,所以考慮將報文解析移動後面的文章序列了。其實這篇文章,本身我預計打算一天完成的,後面查二進制協議和文本協議的區別,倒是讓我花了不少時間,這到讓我頗為意外。

參考資料

  • HTTP/2 中的多路複用是什麼意思 https://stackoverflow.com/que...
  • Transfer-Encoding:chunked詳解 https://blog.csdn.net/qq_3233...
  • How does HTTP2 solve Head of Line blocking (HOL) issue https://stackoverflow.com/que...
  • HTTP Head of line blocking: Why responses must come back in order? https://stackoverflow.com/que...
  • What is HTTP "Host" header? https://stackoverflow.com/que...
  • Why is it said that HTTP2 is a binary protocol? https://stackoverflow.com/que...
  • How to enable http2 using spring boot and tomcat without SSL configuration https://stackoverflow.com/que...
  • Binary vs Text https://dev.to/cacilhas/binar...
  • 透視 HTTP 協議 https://zq99299.github.io/not...
  • HTTP/2 官網 https://httpwg.org/specs/rfc9...
user avatar tengteng_5c7902af4b01e 頭像
1 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.