http2協(xié)議 · http2講解

2018-06-30 19:21 更新

6. http2協(xié)議

背景介紹就到此為止了,歷史的腳步已經(jīng)將我們推到了今天。現(xiàn)在讓我們深入看看該協(xié)議的規(guī)范,看看那些細(xì)節(jié)和概念。

+

6.1. 二進(jìn)制

http2是一個二進(jìn)制協(xié)議。

+

仔細(xì)想想,如果你是一個曾經(jīng)跟互聯(lián)網(wǎng)協(xié)議打過交道,那你很可能會本能反對二進(jìn)制協(xié)議,你甚至準(zhǔn)備好了一大堆理由來證明基于文本/ascii的協(xié)議是多么的有用,正如你曾無數(shù)次地通過telnet等應(yīng)用手工地輸入HTTP來發(fā)起請求。

+

基于二進(jìn)制的http2可以使成幀的使用變得更為便捷。在HTTP1.1和其他基于文本的協(xié)議中,對幀的起始和結(jié)束識別起來相當(dāng)復(fù)雜。而通過移除掉可選的空白符以及其他冗余后,再來實現(xiàn)這些會變得更容易。

+

而另一方面,這項決議同樣使得我們可以更加便捷的從幀結(jié)構(gòu)中分離出那部分協(xié)議本身的內(nèi)容。而在HTTP1中,各個部分相互交織,猶如一團(tuán)亂麻。

+

事實上,由于協(xié)議提供了壓縮這一特性,而其經(jīng)常運行在TLS之上的事實又再次降低了基于純文本實現(xiàn)的價值,反正也沒辦法直接從數(shù)據(jù)流上看到文本。因此通常情況下,我們必須習(xí)慣使用類似Wireshark這樣的工具對http2的協(xié)議層一探究竟。

+

我們可以使用curl這樣的工具來調(diào)試協(xié)議,而如果要進(jìn)一步地分析網(wǎng)絡(luò)數(shù)據(jù)流則需要諸如Wireshark這樣的http2解析器。

+

6.2. 二進(jìn)制格式

http2會發(fā)送有著不同類型的二進(jìn)制幀,但他們都有如下的公共字段:Type, Length, Flags, Stream Identifier和frame payload

+

規(guī)范中一共定義了10種不同的幀,其中最基礎(chǔ)的兩種分別對應(yīng)于HTTP 1.1的DATA和HEADERS。之后我會更詳細(xì)的介紹它們其中的一部分。

+

6.3. 多路復(fù)用的流

上一節(jié)提到的Stream Identifier將http2連接上傳輸?shù)拿總€幀都關(guān)聯(lián)到一個“流”。流是一個獨立的,雙向的幀序列可以通過一個http2的連接在服務(wù)端與客戶端之間不斷的交換數(shù)據(jù)。

+

每個單獨的http2連接都可以包含多個并發(fā)的流,這些流中交錯的包含著來自兩端的幀。流既可以被客戶端/服務(wù)器端單方面的建立和使用,也可以被雙方共享,或者被任意一邊關(guān)閉。在流里面,每一幀發(fā)送的順序非常關(guān)鍵。接收方會按照收到幀的順序來進(jìn)行處理。

+

流的多路復(fù)用意味著在同一連接中來自各個流的數(shù)據(jù)包會被混合在一起。就好像兩個(或者更多)獨立的“數(shù)據(jù)列車”被拼湊到了一輛列車上,但它們最終會在終點站被分開。下圖就是兩列“數(shù)據(jù)火車”的示例

+

它們就是這樣通過多路復(fù)用的方式被組裝到了同一列火車上。

+

6.4. 優(yōu)先級和依賴性

每個流都包含一個優(yōu)先級(也就是“權(quán)重”),它被用來告訴對端哪個流更重要。當(dāng)資源有限的時候,服務(wù)器會根據(jù)優(yōu)先級來選擇應(yīng)該先發(fā)送哪些流。

+

借助于PRIORITY幀,客戶端同樣可以告知服務(wù)器當(dāng)前的流依賴于其他哪個流。該功能讓客戶端能建立一個優(yōu)先級“樹”,所有“子流”會依賴于“父流”的傳輸完成情況。

+

優(yōu)先級和依賴關(guān)系可以在傳輸過程中被動態(tài)的改變。這樣當(dāng)用戶滾動一個全是圖片的頁面的時候,瀏覽器就能夠指定哪個圖片擁有更高的優(yōu)先級。或者是在你切換標(biāo)簽頁的時候,瀏覽器可以提升新切換到頁面所包含流的優(yōu)先級。

+

6.5. 頭壓縮

HTTP是一種無狀態(tài)的協(xié)議。簡而言之,這意味著每個請求必須要攜帶服務(wù)器需要的所有細(xì)節(jié),而不是讓服務(wù)器保存住之前請求的元數(shù)據(jù)。因為http2并沒有改變這個范式,所以它也以同樣原理工作。

+

這也保證了HTTP可重復(fù)性。當(dāng)一個客戶端從同一服務(wù)器請求了大量資源(例如頁面的圖片)的時候,所有這些請求看起來幾乎都是一致的,而這些大量一致的東西則正好值得被壓縮。

+

當(dāng)每個頁面資源的個數(shù)上升的時候,cookies和請求的大小都會增加。cookies需要被包含在所有請求中,且他們在多個請求中經(jīng)常是一模一樣的。

+

HTTP 1.1請求的大小正變得越來越大,有時甚至?xí)笥赥CP窗口的初始大小,這會嚴(yán)重拖累發(fā)送請求的速度。因為它們需要等待帶著ACK的響應(yīng)回來以后,才能繼續(xù)被發(fā)送。這也是另一個需要壓縮的理由。

+

6.5.1. 壓縮是非常棘手的課題

HTTPS和SPDY的壓縮機(jī)制被發(fā)現(xiàn)有受BREACHCRIME攻擊的隱患。通過向流中注入一些已知的文本來觀察輸出的變化,攻擊者可以從加密的載荷中推導(dǎo)出原始發(fā)送的數(shù)據(jù)。

+

為協(xié)議的動態(tài)內(nèi)容進(jìn)行壓縮并使其免于被攻擊,需要仔細(xì)且全面的考慮,而這也正是HTTPbis小組嘗試去做的。

+

HPACK,HTTP/2頭部壓縮,顧名思義它是一個專為http2頭部設(shè)計的壓縮格式。確切的講,它甚至被制定寫入在另外一個單獨的草案里。新的格式同時引入了一些其他對策讓破解壓縮變得困難,例如采用幀的可選填充和用一個bit作為標(biāo)記,來讓中間人不壓縮指定的頭部。

+

用Roberto Peon(HPACK的設(shè)計者之一)的話說

+

“HPACK旨在提供一個一致性的實現(xiàn)使信息量的損失盡可能少,使編解碼快速而方便,使接收方能控制壓縮文本的大小,允許代理重新建立索引(如,通過代理在前后端共享狀態(tài)),以及對哈夫曼編碼串的更快速比較”

+

6.6. 重置 - 后悔藥

HTTP 1.1的有一個缺點是:當(dāng)一個含有確切值的Content-Length的HTTP消息被送出之后,你就很難中斷它了。當(dāng)然,通常你可以斷開整個TCP鏈接(但也不總是可以這樣),但這樣導(dǎo)致的代價就是需要通過三次握手來重新建立一個新的TCP連接。

+

一個更好的方案是只終止當(dāng)前傳輸?shù)南⒉⒅匦掳l(fā)送一個新的。在http2里面,我們可以通過發(fā)送RST_STREAM幀來實現(xiàn)這種需求,從而避免浪費帶寬和中斷已有的連接。

+

6.7. 服務(wù)器推送

這個功能通常被稱作“緩存推送”。主要的思想是:當(dāng)一個客戶端請求資源X,而服務(wù)器知道它很可能也需要資源Z的情況下,服務(wù)器可以在客戶端發(fā)送請求前,主動將資源Z推送給客戶端。這個功能幫助客戶端將Z放進(jìn)緩存以備將來之需。

+

服務(wù)器推送需要客戶端顯式的允許服務(wù)器提供該功能。但即使如此,客戶端依然能自主選擇是否需要中斷該推送的流。如果不需要的話,客戶端可以通過發(fā)送一個RST_STREAM幀來中止。

+

6.8. 流量控制

每個http2流都擁有自己的公示的流量窗口,它可以限制另一端發(fā)送數(shù)據(jù)。如果你正好知道SSH的工作原理的話,這兩者非常相似。

+

對于每個流來說,兩端都必須告訴對方自己還有足夠的空間來處理新的數(shù)據(jù),而在該窗口被擴(kuò)大前,另一端只被允許發(fā)送這么多數(shù)據(jù)。

+

而只有數(shù)據(jù)幀會受到流量控制。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號