The standardization effort was supported by Chrome, Opera, Firefox,[9] Internet Explorer 11, Safari, Amazon Silk, and Edge browsers.[10] Most major browsers had added HTTP/2 support by the end of 2015.[11] According to W3Techs, as of November 2017, 20.5% of the top 10 million websites supported HTTP/2.
這是一段來自維基百科的關(guān)于HTTP2的說明帮非,截止2015年底,主流瀏覽器都已經(jīng)對HTTP2做了支持兑宇,根據(jù)2017年11月的W3Techs報(bào)告說明启上,全球有1/5的大型網(wǎng)站都已經(jīng)使用了HTTP2了邢隧。作為碼農(nóng)的你已經(jīng)可以預(yù)料HTTP2的時(shí)代即將到來,對于HTTP2的技術(shù)細(xì)節(jié)你都準(zhǔn)備好了么冈在?
HTTP2的設(shè)計(jì)要點(diǎn)
Header壓縮
Server Push
Pipelining & Mulplexing
我們平常聽到的GZIP壓縮僅僅是針對HTTP請求的Body部分進(jìn)行的倒慧,這只能算是半壓縮。對于很多API服務(wù)來說,返回的內(nèi)容體其實(shí)并不大纫谅,這個(gè)時(shí)候請求頭就占據(jù)了大部分流量炫贤。HTTP2將魔爪伸到了HTTP頭部,這回是徹底的對整個(gè)請求都進(jìn)行壓縮了付秕。
HTTP2的頭壓縮原理完全不同于HTTP1.1兰珍,它將常用的HEADER鍵值對映射到一個(gè)靜態(tài)表里面的索引值,于是很多頭部的鍵值對使用一個(gè)位置索引來表示就可以了询吴。這樣便大大節(jié)省了頭部消息的長度掠河。對于那些不常用的自定義的頭部會使用一個(gè)動態(tài)表來維護(hù),具體原理有一定復(fù)雜度猛计,這里就不再啰嗦了唠摹。
Server Push不同于Websocket,Server Push一般是指服務(wù)器主動向客戶端推送數(shù)據(jù)有滑,這是一種單向的主動推送跃闹,而WebSocket是雙向的,這兩種技術(shù)不是競爭關(guān)系毛好。Server Push可以用在服務(wù)器主動向客戶端推送靜態(tài)資源,比如瀏覽器請求index.html時(shí)苛秕,服務(wù)器除了返回網(wǎng)頁內(nèi)容外肌访,還會將index.html頁面里面的各種css和js一起推送到瀏覽器緩存起來,當(dāng)瀏覽器分析了網(wǎng)頁內(nèi)容發(fā)現(xiàn)靜態(tài)資源時(shí)艇劫,不需要再去服務(wù)器請求一次吼驶,它只需要從緩存里直接拿就可以了。不過現(xiàn)代的網(wǎng)站的靜態(tài)資源大多都是CDN架構(gòu)的店煞,靜態(tài)資源都在第三方服務(wù)器蟹演,Server Push在這方面作用并不大。Server Push還可以用在推送通知消息顷蟀,比如誰關(guān)注了你酒请,誰給你點(diǎn)了贊等,這個(gè)可以替代古老的Comet技術(shù)和近幾年Google推廣的SPDY協(xié)議鸣个,它需要服務(wù)器維持當(dāng)前的TCP通道不關(guān)閉羞反,需要持續(xù)占用服務(wù)器資源。
Pipeline是指后一個(gè)HTTP請求無需等待前一個(gè)HTTP請求返回結(jié)果就可以提前發(fā)起囤萤。HTTP1.1也有Pipeline支持昼窗,但是有所不足,并行的還不夠徹底涛舍。它可以提前發(fā)起請求澄惊,但是卻限定了返回結(jié)果必須和收到請求的順序保持一致而不能亂序。如果第一個(gè)請求服務(wù)器處理慢了,那么后續(xù)的返回結(jié)果客戶端無法立即收到掸驱,而必須等到第一個(gè)結(jié)果全部返回了才行窘哈。HTTP2則解決了這個(gè)問題,它支持亂序返回亭敢,甚至不同請求的返回結(jié)果的分塊【HTTP Chunk】也可以交叉返回而不會混亂滚婉,這種技術(shù)稱之為Multiplexing【多路復(fù)用】。
HTTP2底層協(xié)議
HTTP2協(xié)議是二進(jìn)制協(xié)議帅刀,不同于HTTP1.1的文本協(xié)議让腹。文本協(xié)議是以特殊的符號結(jié)尾【換行回車符】來分割消息的,而二進(jìn)制協(xié)議是通過字節(jié)長度來分割消息扣溺。二進(jìn)制協(xié)議雖然直觀性不如文本協(xié)議骇窍,但是在實(shí)現(xiàn)的時(shí)候要簡單直接一些。
HTTP2為支持多路復(fù)用锥余,在同一條TCP通道上支持發(fā)送多個(gè)資源/請求腹纳,將每條資源/請求定義為一個(gè)Stream【流】,同一個(gè)TCP通道可以傳輸多個(gè)Stream驱犹。同時(shí)為了支持多個(gè)資源的并行交錯(cuò)發(fā)送嘲恍,將Stream再次分割為多個(gè)Frame【幀】,幀與幀之間可以交錯(cuò)發(fā)送雄驹。接收端通過流ID將這些幀組裝起來佃牛,通一個(gè)流ID的幀屬于同一個(gè)資源/請求。因?yàn)門CP協(xié)議已經(jīng)可以保證消息包是有序的医舆,所以接收端不必?fù)?dān)心亂序問題俘侠。
HTTP2的幀格式非常簡單,就是長度+類型+標(biāo)志位+流ID+PayLoad蔬将,長度就是PayLoad的字節(jié)數(shù)爷速,類型為一個(gè)字節(jié),標(biāo)志位為1個(gè)字節(jié)霞怀,流ID為4個(gè)字節(jié)惫东,剩下的長度就是PayLoad。不同類型的幀PayLoad不一樣里烦,標(biāo)志位也不一樣凿蒜。
HTTP2標(biāo)準(zhǔn)里定義了10種類型的幀。
HEADERS幀 頭信息胁黑,對應(yīng)于HTTP HEADER
DATA幀 對應(yīng)于HTTP Response Body
PRIORITY幀 用于調(diào)整流的優(yōu)先級
RST_STREAM幀 流終止幀废封,用于中斷資源的傳輸
SETTINGS幀 用戶客戶服務(wù)器交流連接配置信息
PUSH_PROMISE幀 服務(wù)器向客戶端主動推送資源
GOAWAY幀 通知對方斷開連接
PING幀 心跳幀,檢測往返時(shí)間和連接可用性
WINDOW_UPDATE幀 調(diào)整幀大小
CONTINUATION幀 HEADERS太大時(shí)的續(xù)幀
HTTP2標(biāo)準(zhǔn)定義了3個(gè)標(biāo)志位
END_STREAM 流結(jié)束標(biāo)志丧蘸,表示當(dāng)前幀是流的最后一個(gè)幀
END_HEADERS 頭結(jié)束表示漂洋,表示當(dāng)前幀是頭信息的最后一個(gè)幀
PADDED 填充標(biāo)志遥皂,在數(shù)據(jù)Payload里填充無用信息,用于干擾信道監(jiān)聽
對于一個(gè)普通的GET請求來說刽漂,它使用一個(gè)HEADERS幀就可以表達(dá)演训。HEADERS幀會設(shè)置標(biāo)志位END_STREAM和END_HEADERS表示當(dāng)前幀是一個(gè)完整的HEADERS幀,也是一個(gè)完整的HTTP請求流贝咙。
對于一個(gè)普通的GET請求響應(yīng)來說样悟,它使用一個(gè)HEADERS幀和多個(gè)DATA幀就可以表達(dá)。HEADERS幀設(shè)置END_HEADERS表示當(dāng)前幀是一個(gè)完整的HEADERS幀庭猩,后面的DATA幀表示返回的數(shù)據(jù)窟她,對應(yīng)Response Body。在HTTP1.1里面返回的Body長度較大蔼水,就需要分Chunk進(jìn)行傳輸震糖。HTTP2是通過分成多個(gè)DATA幀來進(jìn)行的,最后一個(gè)DATA幀有一個(gè)END_STREAM標(biāo)記表示Body的結(jié)束趴腋。
如果HEADERS太大無法用一個(gè)HEADERS幀表達(dá)吊说,可以后面跟多個(gè)CONTINUATION幀,最后一個(gè)幀附加END_HEADERS標(biāo)志即可优炬。
在服務(wù)器主動向客戶端推送資源時(shí)颁井,同一個(gè)資源流里不使用HEADERS幀,取而代之的是PUSH_PROMISE幀穿剖,表示服務(wù)器承諾客戶端即將推送指定資源數(shù)據(jù)蚤蔓,用于區(qū)別一個(gè)常規(guī)的HTTP GET資源請求。
如果一個(gè)TCP連接正在被用于客戶端從服務(wù)器下載一個(gè)大型文件糊余,那么客戶端取消發(fā)送這個(gè)文件的辦法只有一個(gè),就是關(guān)閉連接单寂。HTTP2則可以在不關(guān)閉連接的情況下終止發(fā)送文件贬芥,客戶端向服務(wù)器發(fā)送一個(gè)RST_STREAM幀通知服務(wù)器停止相應(yīng)的資源流即可。這個(gè)連接還可以繼續(xù)服務(wù)其它的請求宣决。
HTTP2服務(wù)器接收到一個(gè)客戶端的連接時(shí)蘸劈,第一個(gè)要干的事就是和客戶端交換SETTINGS幀信息,告知對方一些交互元信息的設(shè)置尊沸,例如是否開啟服務(wù)器推送威沫,并行的最大流數(shù)量,單幀最大長度等洼专。
在客戶端觀看視頻流時(shí)棒掠,如果服務(wù)器發(fā)送的太慢會影響觀看體驗(yàn),如果發(fā)的太快屁商,會對客戶端的瀏覽器緩存造成壓力烟很。客戶端可以使用WINDOW_UPDATE幀通知服務(wù)器調(diào)整幀窗口大小進(jìn)而控制服務(wù)區(qū)發(fā)送的數(shù)據(jù)速率。
閱讀相關(guān)文章雾袱,關(guān)注微信公眾號/知乎專欄/頭條號【碼洞】