鍍金池/ 教程/ Linux/ http2 協(xié)議
后http2時(shí)代
升級HTTP
擴(kuò)展
擴(kuò)展閱讀
致謝
http2 的世界
curl中的http2
Chromium里的http2
背景
Firefox里的http2
HTTP 的現(xiàn)狀
http2 協(xié)議
http2 的基本概念
那些年,克服延遲之道

http2 協(xié)議

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

6.1. 二進(jìn)制

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

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

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

另一方面,從幀結(jié)構(gòu)中分離出協(xié)議本身的部分也變得更容易。而在HTTP1中,各個(gè)部分相互交織,一團(tuán)亂麻。

協(xié)議的壓縮特點(diǎn)和其經(jīng)常運(yùn)行在TLS之上的事實(shí)讓純文本的屬性值變得毫無作用,畢竟也無法從數(shù)據(jù)流上看到文本。我們需要習(xí)慣于使用類似Wireshark的工具來從協(xié)議層面對http2一探究竟。

調(diào)試這樣的協(xié)議將需要curl這樣的工具,要進(jìn)一步地分析網(wǎng)絡(luò)數(shù)據(jù)流需要類似Wireshark的http2解析器。

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

http2發(fā)送二進(jìn)制幀。幀的類型有很多種,但他們都有如下的公共字段:

Type, Length, Flags, Steam Identifier和frame payload

http://wiki.jikexueyuan.com/project/http-2-explained/images/binary.png" alt="" />

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

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

上一節(jié)提到的Stream Identifier定義了二進(jìn)制幀的格式,http2連接上傳輸?shù)拿總€(gè)幀都關(guān)聯(lián)到一個(gè)“流”。流是一個(gè)邏輯上的聯(lián)合,一個(gè)獨(dú)立的,雙向的幀序列。這一系列幀在客戶端和服務(wù)器中通過http2連接進(jìn)行交換。

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

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

http://wiki.jikexueyuan.com/project/http-2-explained/images/multiplexing_1.png" alt="" />

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

http://wiki.jikexueyuan.com/project/http-2-explained/images/multiplexing_2.png" alt="" />

在http2里面,我們很容易可以看到10個(gè)甚至100個(gè)同時(shí)并存的流。創(chuàng)建一個(gè)新的流的代價(jià)也非常低。

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

每個(gè)流都包含一個(gè)優(yōu)先級,優(yōu)先級被用來告訴對端哪個(gè)流更重要。

優(yōu)先級的工作機(jī)制在協(xié)議中被改變多次,至今仍在討論。重點(diǎn)在于要讓客戶端能指定哪個(gè)流更重要,并且提供一個(gè)依賴參數(shù)來指定流的依賴關(guān)系。

優(yōu)先級能動(dòng)態(tài)的被改變。這樣當(dāng)用戶滾動(dòng)一個(gè)全是圖片的頁面的時(shí)候,瀏覽器能夠指定哪個(gè)圖片有更高的優(yōu)先級?;蛘呤窃谀闱袚Q標(biāo)簽頁的時(shí)候,瀏覽器可以提升新切換到頁面所包含流的優(yōu)先級。

6.5. 頭壓縮

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

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

當(dāng)每個(gè)頁面資源的個(gè)數(shù)上升的時(shí)候,cookies和請求的大小都會(huì)增加,而每個(gè)請求都會(huì)包含的cookie幾乎是一模一樣的。

http://wiki.jikexueyuan.com/project/http-2-explained/images/compression.png" alt="" />

HTTP 1.1請求的大小變得越來越大,有時(shí)甚至?xí)笥赥CP窗口的初始大小,這會(huì)嚴(yán)重拖累發(fā)送請求的速度。因?yàn)樗鼈冃枰却龓е鳤CK的響應(yīng)回來以后,才能繼續(xù)被發(fā)送。這也是需要壓縮的理由。

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

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

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

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

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

6.6. 重置 - 后悔藥

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

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

6.7. 服務(wù)器推送

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

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

6.8. 流量控制

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

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

上一篇:http2 的世界