http協(xié)議是互聯(lián)網(wǎng)上使用最廣泛毕莱、最通用的通訊協(xié)議,也可以說(shuō)是互聯(lián)網(wǎng)通訊協(xié)議的事實(shí)標(biāo)準(zhǔn)颅夺。任何一個(gè)語(yǔ)言朋截,只要說(shuō)涉及通訊,就不可能不支持http協(xié)議吧黄。這使得http協(xié)議天生具備了良好的跨語(yǔ)言特性部服,但是傳統(tǒng)的http協(xié)議由于制定的年代久遠(yuǎn),通訊的效率不是很高拗慨。http/2是http規(guī)范的一個(gè)最新版本饲宿,在各方面都有了大幅的升級(jí)厦酬,本文對(duì)于該協(xié)議做一個(gè)簡(jiǎn)單介紹胆描。
HTTP/1.1
說(shuō)到http瘫想,那就應(yīng)該先了解一下http協(xié)議的發(fā)展歷史。關(guān)于http協(xié)議的歷史昌讲,可以參考阮一峰老師的這篇博客文章 HTTP 協(xié)議入門(mén),里面介紹的比較詳細(xì)了国夜。簡(jiǎn)單來(lái)說(shuō)http先后存在0.9
、1.0
短绸、1.1
三個(gè)版本车吹,我們目前上網(wǎng)使用最廣泛的是http/1.1
協(xié)議,發(fā)布于1997年醋闭,距今已經(jīng)20多年了窄驹,至今仍然是訪(fǎng)問(wèn)網(wǎng)站的主流協(xié)議(真是老而彌堅(jiān)啊)证逻。http/1.1的報(bào)文格式如下:
request報(bào)文
response報(bào)文
http/1.1的問(wèn)題
http協(xié)議早期為互聯(lián)網(wǎng)的普及做出了巨大的貢獻(xiàn)乐埠,構(gòu)建了現(xiàn)代互聯(lián)網(wǎng)的基礎(chǔ)架構(gòu),但是由于協(xié)議制定的時(shí)間較早囚企,在很多方面還是有著局限性丈咐,在互聯(lián)網(wǎng)高速發(fā)展,信息爆炸的今天龙宏,難免有些捉襟見(jiàn)肘棵逊。主要體現(xiàn)在以下幾個(gè)方面:
- 傳輸報(bào)文為ascii文本形式,對(duì)于http header不會(huì)進(jìn)行壓縮银酗。這樣對(duì)于可讀性是比較友好辆影,但對(duì)于計(jì)算機(jī)不太友好,此外傳輸效率較低
- 請(qǐng)求只能由客戶(hù)端發(fā)起黍特,不能由服務(wù)端發(fā)起蛙讥。這種模式限制了一些主動(dòng)推送或者有雙工需求的使用場(chǎng)景,當(dāng)然也有比如websocket之類(lèi)的解決方案衅澈,但那嚴(yán)格來(lái)說(shuō)已經(jīng)不屬于http協(xié)議的范疇了键菱。
- 同步阻塞通訊:其實(shí)在http/1.1中已經(jīng)默認(rèn)使用了持久連接(persistent connection),可以做到多個(gè)請(qǐng)求復(fù)用同一個(gè)tcp連接今布,同時(shí)利用管道機(jī)制(pipelining)经备,可以讓請(qǐng)求同時(shí)在一個(gè)tcp連接上發(fā)送,但是http本質(zhì)上還是一個(gè)
請(qǐng)求/響應(yīng)
模型部默,服務(wù)端仍然需要按照請(qǐng)求的順序依次回復(fù)侵蒙,不能亂序回復(fù)。這樣要是前面的回應(yīng)特別慢傅蹂,后面就會(huì)有許多請(qǐng)求排隊(duì)等著纷闺。這稱(chēng)為"隊(duì)頭堵塞"(Head-of-line blocking)算凿。 - 由于隊(duì)頭堵塞問(wèn)題的存在,在客戶(hù)端要下載大量資源的情況下犁功,不得不和服務(wù)器建立多個(gè)TCP連接(大部分瀏覽器允許最多建立6個(gè)和指定服務(wù)器的持久連接)氓轰,達(dá)到并發(fā)傳輸?shù)男Ч娝苤裕⒑弯N(xiāo)毀tcp連接的成本是非常高昂的(如果是https就更高)署鸡,同時(shí)也增加了服務(wù)端的資源消耗。
基于以上的這些痛點(diǎn)限嫌,催生出了http/2靴庆。
HTTP/2
SPDY
http/2起源于谷歌的SPDY項(xiàng)目(沒(méi)錯(cuò),又是谷歌-_-),于 2009 年年中發(fā)布怒医,其主要目標(biāo)是通過(guò)解決 HTTP/1.1 中廣為人知的一些性能限制來(lái)減少網(wǎng)頁(yè)的加載延遲(那些廣為人知的限制我在上面都提到了)炉抒。具體來(lái)說(shuō),這個(gè)項(xiàng)目設(shè)定的目標(biāo)如下:
- 頁(yè)面加載時(shí)間 (PLT) 減少 50%稚叹。
- 無(wú)需網(wǎng)站作者修改任何內(nèi)容焰薄。
- 將部署復(fù)雜性降至最低,無(wú)需變更網(wǎng)絡(luò)基礎(chǔ)設(shè)施入录。
- 與開(kāi)源社區(qū)合作開(kāi)發(fā)這個(gè)新協(xié)議蛤奥。
- 收集真實(shí)性能數(shù)據(jù),驗(yàn)證這個(gè)實(shí)驗(yàn)性協(xié)議是否有效僚稿。
到了2012 年凡桥,這個(gè)新的實(shí)驗(yàn)性協(xié)議得到了 Chrome、Firefox 和 Opera 的支持蚀同,越來(lái)越多的大型網(wǎng)站(如 Google缅刽、Twitter、Facebook)和小型網(wǎng)站開(kāi)始在其基礎(chǔ)設(shè)施內(nèi)部署 SPDY蠢络。事實(shí)上衰猛,在被行業(yè)越來(lái)越多的采用之后,SPDY 已經(jīng)具備了成為一個(gè)標(biāo)準(zhǔn)的條件刹孔。
觀(guān)察到這一趨勢(shì)后啡省,HTTP 工作組 (HTTP-WG) 將這一工作提上議事日程,吸取 SPDY 的經(jīng)驗(yàn)教訓(xùn)髓霞,并在此基礎(chǔ)上制定了官方“HTTP/2”標(biāo)準(zhǔn)卦睹。在擬定宣言草案、向社會(huì)征集 HTTP/2 建議并經(jīng)過(guò)內(nèi)部討論之后方库,HTTP-WG 決定將 SPDY 規(guī)范作為新 HTTP/2 協(xié)議的基礎(chǔ)结序。2015 年初,IESG 審閱了新的 HTTP/2 標(biāo)準(zhǔn)并批準(zhǔn)發(fā)布纵潦。
二進(jìn)制分層幀
HTTP/2 所有性能增強(qiáng)的核心在于新的二進(jìn)制分幀層徐鹤,它定義了如何封裝 HTTP 消息并在客戶(hù)端與服務(wù)器之間傳輸垃环。
可以看到,http的語(yǔ)義都沒(méi)有變化(包括各種動(dòng)詞返敬、方法遂庄、標(biāo)頭),不同的是傳輸期間對(duì)它們的編碼方式變了救赐。HTTP/1.x 協(xié)議以換行符作為純文本的分隔符涧团,而 HTTP/2 將所有傳輸?shù)男畔⒎指顬楦〉南⒑蛶⒉捎枚M(jìn)制格式對(duì)它們編碼经磅。原來(lái)的http header封入HEADERS frame
,原來(lái)的http body封入DATA frame
。這樣一來(lái)钮追,客戶(hù)端和服務(wù)器要互相理解预厌,勢(shì)必都要支持http/2的報(bào)文格式,由于引入了新的二進(jìn)制分層幀的概念元媚,這個(gè)協(xié)議并不向后兼容轧叽,這也是它叫做http/2而不是http/1.2 的根本原因。
數(shù)據(jù)流刊棕、消息和幀
新的二進(jìn)制分幀機(jī)制改變了客戶(hù)端與服務(wù)器之間交換數(shù)據(jù)的方式炭晒。 為了說(shuō)明這個(gè)過(guò)程,我們需要了解 HTTP/2 的三個(gè)概念:
數(shù)據(jù)流:已建立的連接內(nèi)的雙向字節(jié)流甥角,可以承載一條或多條消息网严。
消息:與邏輯請(qǐng)求或響應(yīng)消息對(duì)應(yīng)的完整的一系列幀。
幀:HTTP/2 通信的最小單位嗤无,每個(gè)幀都包含幀頭震束,至少也會(huì)標(biāo)識(shí)出當(dāng)前幀所屬的數(shù)據(jù)流。
這些概念的關(guān)系總結(jié)如下:所有通信都在一個(gè) TCP 連接上完成当犯,此連接可以承載任意數(shù)量的雙向數(shù)據(jù)流垢村。
每個(gè)數(shù)據(jù)流都有一個(gè)唯一的標(biāo)識(shí)符和可選的優(yōu)先級(jí)信息,用于承載雙向消息嚎卫。
每條消息都是一條邏輯 HTTP 消息(例如請(qǐng)求或響應(yīng))嘉栓,包含一個(gè)或多個(gè)幀。
-
幀是最小的通信單位拓诸,承載著特定類(lèi)型的數(shù)據(jù)侵佃,例如 HTTP 標(biāo)頭、消息負(fù)載恰响,等等趣钱。 來(lái)自不同數(shù)據(jù)流的幀可以交錯(cuò)發(fā)送,然后再根據(jù)每個(gè)幀頭的數(shù)據(jù)流標(biāo)識(shí)符重新組裝胚宦。
image.png
簡(jiǎn)言之首有,HTTP/2 將 HTTP 協(xié)議通信分解為二進(jìn)制編碼幀的交換燕垃,這些幀對(duì)應(yīng)著特定數(shù)據(jù)流中的消息。所有這些都在一個(gè) TCP 連接內(nèi)復(fù)用井联。這是 HTTP/2 協(xié)議所有其他功能和性能優(yōu)化的基礎(chǔ)卜壕。
請(qǐng)求與響應(yīng)復(fù)用
在 HTTP/1.x 中,如果客戶(hù)端要想發(fā)起多個(gè)并行請(qǐng)求以提升性能烙常,則必須使用多個(gè) TCP 連接(請(qǐng)參閱使用多個(gè) TCP 連接)轴捎。這是 HTTP/1.x 交付模型的直接結(jié)果,該模型可以保證每個(gè)連接每次只交付一個(gè)響應(yīng)(響應(yīng)排隊(duì))蚕脏。更糟糕的是侦副,這種模型也會(huì)導(dǎo)致隊(duì)首阻塞,從而造成底層 TCP 連接的效率低下驼鞭。
HTTP/2 中新的二進(jìn)制分幀層突破了這些限制秦驯,實(shí)現(xiàn)了完整的請(qǐng)求和響應(yīng)復(fù)用:客戶(hù)端和服務(wù)器可以將 HTTP 消息分解為互不依賴(lài)的幀,然后交錯(cuò)發(fā)送挣棕,最后再在另一端把它們重新組裝起來(lái)译隘。
快照捕捉了同一個(gè)連接內(nèi)并行的多個(gè)數(shù)據(jù)流÷逍模客戶(hù)端正在向服務(wù)器傳輸一個(gè) DATA
幀(數(shù)據(jù)流 5)固耘,與此同時(shí),服務(wù)器正向客戶(hù)端交錯(cuò)發(fā)送數(shù)據(jù)流 1 和數(shù)據(jù)流 3 的一系列幀词身。因此厅目,一個(gè)連接上同時(shí)有三個(gè)并行數(shù)據(jù)流。
將 HTTP 消息分解為獨(dú)立的幀偿枕,交錯(cuò)發(fā)送璧瞬,然后在另一端重新組裝是 HTTP 2 最重要的一項(xiàng)增強(qiáng)。事實(shí)上渐夸,這個(gè)機(jī)制會(huì)在整個(gè)網(wǎng)絡(luò)技術(shù)棧中引發(fā)一系列連鎖反應(yīng)嗤锉,從而帶來(lái)巨大的性能提升,讓我們可以:
- 并行交錯(cuò)地發(fā)送多個(gè)請(qǐng)求墓塌,請(qǐng)求之間互不影響瘟忱。
- 并行交錯(cuò)地發(fā)送多個(gè)響應(yīng),響應(yīng)之間互不干擾苫幢。
- 使用一個(gè)連接并行發(fā)送多個(gè)請(qǐng)求和響應(yīng)访诱。
- 不必再為繞過(guò) HTTP/1.x 限制而做很多工作(請(qǐng)參閱針對(duì) HTTP/1.x 進(jìn)行優(yōu)化,例如級(jí)聯(lián)文件韩肝、image sprites 和域名分片触菜。
- 消除不必要的延遲和提高現(xiàn)有網(wǎng)絡(luò)容量的利用率,從而減少頁(yè)面加載時(shí)間哀峻。
- 等等…
HTTP/2 中的新二進(jìn)制分幀層解決了 HTTP/1.x 中存在的隊(duì)頭阻塞問(wèn)題涡相,也消除了并行處理和發(fā)送請(qǐng)求及響應(yīng)時(shí)對(duì)多個(gè)連接的依賴(lài)哲泊。結(jié)果,應(yīng)用速度更快催蝗、開(kāi)發(fā)更簡(jiǎn)單切威、部署成本更低捎泻。
數(shù)據(jù)流優(yōu)先級(jí)
這個(gè)是http/2協(xié)議的一個(gè)高級(jí)功能恩溅。將 HTTP 消息分解為很多獨(dú)立的幀之后腮敌,我們就可以復(fù)用多個(gè)數(shù)據(jù)流中的幀男窟,客戶(hù)端和服務(wù)器交錯(cuò)發(fā)送和傳輸這些幀的順序就成為關(guān)鍵的性能決定因素。為了做到這一點(diǎn)搓译,HTTP/2 標(biāo)準(zhǔn)允許每個(gè)數(shù)據(jù)流都有一個(gè)關(guān)聯(lián)的權(quán)重和依賴(lài)關(guān)系:
可以向每個(gè)數(shù)據(jù)流分配一個(gè)介于 1 至 256 之間的整數(shù)卖毁。
每個(gè)數(shù)據(jù)流與其他數(shù)據(jù)流之間可以存在顯式依賴(lài)關(guān)系池颈。
數(shù)據(jù)流依賴(lài)關(guān)系和權(quán)重的組合讓客戶(hù)端可以構(gòu)建和傳遞“優(yōu)先級(jí)樹(shù)”遍尺,表明它傾向于如何接收響應(yīng)截酷。反過(guò)來(lái),服務(wù)器可以使用此信息通過(guò)控制 CPU乾戏、內(nèi)存和其他資源的分配設(shè)定數(shù)據(jù)流處理的優(yōu)先級(jí),在資源數(shù)據(jù)可用之后三热,帶寬分配可以確保將高優(yōu)先級(jí)響應(yīng)以最優(yōu)方式傳輸至客戶(hù)端鼓择。
HTTP/2 內(nèi)的數(shù)據(jù)流依賴(lài)關(guān)系通過(guò)將另一個(gè)數(shù)據(jù)流的唯一標(biāo)識(shí)符作為父項(xiàng)引用進(jìn)行聲明;如果忽略標(biāo)識(shí)符就漾,相應(yīng)數(shù)據(jù)流將依賴(lài)于“根數(shù)據(jù)流”呐能。聲明數(shù)據(jù)流依賴(lài)關(guān)系指出,應(yīng)盡可能先向父數(shù)據(jù)流分配資源抑堡,然后再向其依賴(lài)項(xiàng)分配資源摆出。換句話(huà)說(shuō),“請(qǐng)先處理和傳輸響應(yīng) D首妖,然后再處理和傳輸響應(yīng) C”偎漫。
共享相同父項(xiàng)的數(shù)據(jù)流(即,同級(jí)數(shù)據(jù)流)應(yīng)按其權(quán)重比例分配資源有缆。 例如象踊,如果數(shù)據(jù)流 A 的權(quán)重為 12,其同級(jí)數(shù)據(jù)流 B 的權(quán)重為 4棚壁,那么要確定每個(gè)數(shù)據(jù)流應(yīng)接收的資源比例杯矩,請(qǐng)執(zhí)行以下操作:
- 將所有權(quán)重求和:4 + 12 = 16
- 將每個(gè)數(shù)據(jù)流權(quán)重除以總權(quán)重:A = 12/16, B = 4/16因此,數(shù)據(jù)流 A 應(yīng)獲得四分之三的可用資源袖外,數(shù)據(jù)流 B 應(yīng)獲得四分之一的可用資源史隆;數(shù)據(jù)流 B 獲得的資源是數(shù)據(jù)流 A 所獲資源的三分之一。我們來(lái)看一下上圖中的其他幾個(gè)動(dòng)手示例:順序?yàn)閺淖蟮接遥?/li>
- 數(shù)據(jù)流 A 和數(shù)據(jù)流 B 都沒(méi)有指定父依賴(lài)項(xiàng)曼验,依賴(lài)于顯式“根數(shù)據(jù)流”泌射;A 的權(quán)重為 12粘姜,B 的權(quán)重為 4。因此魄幕,根據(jù)比例權(quán)重:數(shù)據(jù)流 B 獲得的資源是 A 所獲資源的三分之一相艇。
- 數(shù)據(jù)流 D 依賴(lài)于根數(shù)據(jù)流;C 依賴(lài)于 D纯陨。因此坛芽,D 應(yīng)先于 C 獲得完整資源分配。權(quán)重不重要翼抠,因?yàn)?C 的依賴(lài)關(guān)系擁有更高的優(yōu)先級(jí)咙轩。
- 數(shù)據(jù)流 D 應(yīng)先于 C 獲得完整資源分配;C 應(yīng)先于 A 和 B 獲得完整資源分配阴颖;數(shù)據(jù)流 B 獲得的資源是 A 所獲資源的三分之一活喊。
- 數(shù)據(jù)流 D 應(yīng)先于 E 和 C 獲得完整資源分配;E 和 C 應(yīng)先于 A 和 B 獲得相同的資源分配量愧;A 和 B 應(yīng)基于其權(quán)重獲得比例分配钾菊。
如上面的示例所示,數(shù)據(jù)流依賴(lài)關(guān)系和權(quán)重的組合明確表達(dá)了資源優(yōu)先級(jí)偎肃,這是一種用于提升瀏覽性能的關(guān)鍵功能煞烫,網(wǎng)絡(luò)中擁有多種資源類(lèi)型,它們的依賴(lài)關(guān)系和權(quán)重各不相同(比如在一個(gè)網(wǎng)頁(yè)上累颂,我們應(yīng)該先優(yōu)先保障加載文本資源滞详,然后再是圖片和視頻)。不僅如此紊馏,HTTP/2 協(xié)議還允許客戶(hù)端隨時(shí)更新這些優(yōu)先級(jí)料饥,進(jìn)一步優(yōu)化了瀏覽器性能。換句話(huà)說(shuō)朱监,我們可以根據(jù)用戶(hù)互動(dòng)和其他信號(hào)更改依賴(lài)關(guān)系和重新分配權(quán)重岸啡。
每個(gè)來(lái)源一個(gè)連接
這個(gè)是http/2協(xié)議所帶來(lái)的重大性能提升。有了新的分幀機(jī)制后赌朋,HTTP/2 不再依賴(lài)多個(gè) TCP 連接去并行復(fù)用數(shù)據(jù)流凰狞;每個(gè)數(shù)據(jù)流都拆分成很多幀,而這些幀可以交錯(cuò)沛慢,還可以分別設(shè)定優(yōu)先級(jí)赡若。因此,所有 HTTP/2 連接都是永久的团甲,而且僅需要每個(gè)來(lái)源一個(gè)連接逾冬,隨之帶來(lái)諸多性能優(yōu)勢(shì)。
大多數(shù) HTTP 傳輸都是短暫且急促的,而 TCP 則針對(duì)長(zhǎng)時(shí)間的批量數(shù)據(jù)傳輸進(jìn)行了優(yōu)化身腻。 通過(guò)重用相同的連接产还,HTTP/2 既可以更有效地利用每個(gè) TCP 連接,也可以顯著降低整體協(xié)議開(kāi)銷(xiāo)嘀趟。不僅如此脐区,使用更少的連接還可以減少占用的內(nèi)存和處理空間,也可以縮短完整連接路徑(即她按,客戶(hù)端牛隅、可信中介和源服務(wù)器之間的路徑)這降低了整體運(yùn)行成本并提高了網(wǎng)絡(luò)利用率和容量。 因此酌泰,遷移到 HTTP/2 不僅可以減少網(wǎng)絡(luò)延遲媒佣,還有助于提高通量和降低運(yùn)行成本。
連接數(shù)量減少對(duì)提升 HTTPS 部署的性能來(lái)說(shuō)是一項(xiàng)特別重要的功能:眾所周知建立基于TLS的http連接非常耗時(shí)陵刹,http/2可以減少開(kāi)銷(xiāo)較大的 TLS 連接數(shù)默伍、提升會(huì)話(huà)重用率,以及從整體上減少所需的客戶(hù)端和服務(wù)器資源衰琐。
流控制
流控制是一種阻止發(fā)送方向接收方發(fā)送大量數(shù)據(jù)的機(jī)制也糊,以免超出后者的需求或處理能力:發(fā)送方可能非常繁忙、處于較高的負(fù)載之下羡宙,也可能僅僅希望為特定數(shù)據(jù)流分配固定量的資源显设。例如,客戶(hù)端可能請(qǐng)求了一個(gè)具有較高優(yōu)先級(jí)的大型視頻流辛辨,但是用戶(hù)已經(jīng)暫停視頻,客戶(hù)端現(xiàn)在希望暫蜕悖或限制從服務(wù)器的傳輸斗搞,以免提取和緩沖不必要的數(shù)據(jù)。再比如慷妙,一個(gè)代理服務(wù)器可能具有較快的下游連接和較慢的上游連接僻焚,并且也希望調(diào)節(jié)下游連接傳輸數(shù)據(jù)的速度以匹配上游連接的速度來(lái)控制其資源利用率;等等膝擂。
上述要求會(huì)讓您想到 TCP 流控制嗎虑啤?您應(yīng)當(dāng)想到這一點(diǎn);因?yàn)閱?wèn)題基本相同(請(qǐng)參閱流控制)架馋。不過(guò)狞山,由于 HTTP/2 數(shù)據(jù)流在一個(gè) TCP 連接內(nèi)復(fù)用,TCP 流控制既不夠精細(xì)叉寂,也無(wú)法提供必要的應(yīng)用級(jí) API 來(lái)調(diào)節(jié)各個(gè)數(shù)據(jù)流的傳輸萍启。為了解決這一問(wèn)題,HTTP/2 提供了一組簡(jiǎn)單的構(gòu)建塊,這些構(gòu)建塊允許客戶(hù)端和服務(wù)器實(shí)現(xiàn)其自己的數(shù)據(jù)流和連接級(jí)流控制:
- 流控制具有方向性勘纯。每個(gè)接收方都可以根據(jù)自身需要選擇為每個(gè)數(shù)據(jù)流和整個(gè)連接設(shè)置任意的窗口大小局服。
- 流控制基于信用。每個(gè)接收方都可以公布其初始連接和數(shù)據(jù)流流控制窗口(以字節(jié)為單位)驳遵,每當(dāng)發(fā)送方發(fā)出
DATA
幀時(shí)都會(huì)減小淫奔,在接收方發(fā)出WINDOW_UPDATE
幀時(shí)增大。 - 流控制無(wú)法停用堤结。建立 HTTP/2 連接后唆迁,客戶(hù)端將與服務(wù)器交換
SETTINGS
幀,這會(huì)在兩個(gè)方向上設(shè)置流控制窗口霍殴。流控制窗口的默認(rèn)值設(shè)為 65,535 字節(jié)媒惕,但是接收方可以設(shè)置一個(gè)較大的最大窗口大小(2^31-1
字節(jié))来庭,并在接收到任意數(shù)據(jù)時(shí)通過(guò)發(fā)送WINDOW_UPDATE
幀來(lái)維持這一大小妒蔚。 - 流控制為逐躍點(diǎn)控制,而非端到端控制月弛。即肴盏,可信中介可以使用它來(lái)控制資源使用,以及基于自身?xiàng)l件和啟發(fā)式算法實(shí)現(xiàn)資源分配機(jī)制帽衙。
HTTP/2 未指定任何特定算法來(lái)實(shí)現(xiàn)流控制菜皂。不過(guò),它提供了簡(jiǎn)單的構(gòu)建塊并推遲了客戶(hù)端和服務(wù)器實(shí)現(xiàn)厉萝,可以實(shí)現(xiàn)自定義策略來(lái)調(diào)節(jié)資源使用和分配恍飘,以及實(shí)現(xiàn)新傳輸能力,同時(shí)提升網(wǎng)絡(luò)應(yīng)用的實(shí)際性能和感知性能(請(qǐng)參閱速度谴垫、性能和人類(lèi)感知)章母。
例如,應(yīng)用層流控制允許瀏覽器僅提取一部分特定資源翩剪,通過(guò)將數(shù)據(jù)流流控制窗口減小為零來(lái)暫停提取乳怎,稍后再行恢復(fù)。換句話(huà)說(shuō)前弯,它允許瀏覽器提取圖像預(yù)覽或首次掃描結(jié)果蚪缀,進(jìn)行顯示并允許其他高優(yōu)先級(jí)提取繼續(xù),然后在更關(guān)鍵的資源完成加載后恢復(fù)提取恕出。
服務(wù)器推送
之前介紹過(guò)询枚,HTTP/1.1無(wú)法從服務(wù)器主動(dòng)推送信息給客戶(hù)端,而這是HTTP/2 新增的另一個(gè)強(qiáng)大的新功能剃根,服務(wù)器可以對(duì)一個(gè)客戶(hù)端請(qǐng)求發(fā)送多個(gè)響應(yīng)哩盲。 換句話(huà)說(shuō),除了對(duì)最初請(qǐng)求的響應(yīng)外,服務(wù)器還可以向客戶(hù)端推送額外資源廉油,而無(wú)需客戶(hù)端明確地請(qǐng)求惠险。
HTTP/2 打破了嚴(yán)格的請(qǐng)求-響應(yīng)語(yǔ)義,支持一對(duì)多和服務(wù)器發(fā)起的推送工作流抒线,在瀏覽器內(nèi)外開(kāi)啟了全新的互動(dòng)可能性班巩。這是一項(xiàng)重要功能,對(duì)我們思考協(xié)議嘶炭、協(xié)議用途和使用方式具有重要的長(zhǎng)期影響抱慌。
為什么在瀏覽器中需要一種此類(lèi)機(jī)制呢?一個(gè)典型的網(wǎng)絡(luò)應(yīng)用包含多種資源眨猎,客戶(hù)端需要檢查服務(wù)器提供的文檔才能逐個(gè)找到它們抑进。那為什么不讓服務(wù)器提前推送這些資源,從而減少額外的延遲時(shí)間呢睡陪?服務(wù)器已經(jīng)知道客戶(hù)端下一步要請(qǐng)求什么資源寺渗,這時(shí)候服務(wù)器推送即可派上用場(chǎng)。
事實(shí)上兰迫,如果您在網(wǎng)頁(yè)中內(nèi)聯(lián)過(guò) CSS信殊、JavaScript,或者通過(guò)數(shù)據(jù) URI 內(nèi)聯(lián)過(guò)其他資產(chǎn)(請(qǐng)參閱資源內(nèi)聯(lián))汁果,那么您就已經(jīng)親身體驗(yàn)過(guò)服務(wù)器推送了涡拘。對(duì)于將資源手動(dòng)內(nèi)聯(lián)到文檔中的過(guò)程,我們實(shí)際上是在將資源推送給客戶(hù)端据德,而不是等待客戶(hù)端請(qǐng)求鳄乏。使用 HTTP/2,我們不僅可以實(shí)現(xiàn)相同結(jié)果棘利,還會(huì)獲得其他性能優(yōu)勢(shì)汞窗。 推送資源可以進(jìn)行以下處理:
- 由客戶(hù)端緩存
- 在不同頁(yè)面之間重用
- 與其他資源一起復(fù)用
- 由服務(wù)器設(shè)定優(yōu)先級(jí)
- 被客戶(hù)端拒絕
PUSH_PROMISE 101
所有服務(wù)器推送數(shù)據(jù)流都由 PUSH_PROMISE
幀發(fā)起,表明了服務(wù)器向客戶(hù)端推送所述資源的意圖赡译,并且需要先于請(qǐng)求推送資源的響應(yīng)數(shù)據(jù)傳輸。這種傳輸順序非常重要:客戶(hù)端需要了解服務(wù)器打算推送哪些資源不铆,以免為這些資源創(chuàng)建重復(fù)請(qǐng)求蝌焚。滿(mǎn)足此要求的最簡(jiǎn)單策略是先于父響應(yīng)(即,DATA
幀)發(fā)送所有 PUSH_PROMISE
幀誓斥,其中包含所承諾資源的 HTTP 標(biāo)頭只洒。
在客戶(hù)端接收到 PUSH_PROMISE
幀后,它可以根據(jù)自身情況選擇拒絕數(shù)據(jù)流(通過(guò) RST_STREAM
幀)劳坑。 (如果資源已經(jīng)位于緩存中毕谴,可能會(huì)發(fā)生這種情況。) 這是一個(gè)相對(duì)于 HTTP/1.x 的重要提升。 相比之下涝开,使用資源內(nèi)聯(lián)(一種受歡迎的 HTTP/1.x“優(yōu)化”)等同于“強(qiáng)制推送”:客戶(hù)端無(wú)法選擇拒絕循帐、取消或單獨(dú)處理內(nèi)聯(lián)的資源。
使用 HTTP/2舀武,客戶(hù)端仍然完全掌控服務(wù)器推送的使用方式拄养。客戶(hù)端可以限制并行推送的數(shù)據(jù)流數(shù)量银舱;調(diào)整初始的流控制窗口以控制在數(shù)據(jù)流首次打開(kāi)時(shí)推送的數(shù)據(jù)量瘪匿;或完全停用服務(wù)器推送。這些優(yōu)先級(jí)在 HTTP/2 連接開(kāi)始時(shí)通過(guò) SETTINGS
幀傳輸寻馏,可能隨時(shí)更新棋弥。
推送的每個(gè)資源都是一個(gè)數(shù)據(jù)流,與內(nèi)嵌資源不同诚欠,客戶(hù)端可以對(duì)推送的資源逐一復(fù)用顽染、設(shè)定優(yōu)先級(jí)和處理。 瀏覽器強(qiáng)制執(zhí)行的唯一安全限制是聂薪,推送的資源必須符合原點(diǎn)相同這一政策:服務(wù)器對(duì)所提供內(nèi)容必須具有權(quán)威性家乘。
標(biāo)頭壓縮
每個(gè) HTTP 傳輸都承載一組標(biāo)頭,這些標(biāo)頭說(shuō)明了傳輸?shù)馁Y源及其屬性藏澳。 在 HTTP/1.x 中仁锯,此元數(shù)據(jù)始終以純文本形式,通常會(huì)給每個(gè)傳輸增加 500–800 字節(jié)的開(kāi)銷(xiāo)翔悠。如果使用 HTTP Cookie业崖,增加的開(kāi)銷(xiāo)有時(shí)會(huì)達(dá)到上千字節(jié)。(請(qǐng)參閱測(cè)量和控制協(xié)議開(kāi)銷(xiāo)蓄愁。)為了減少此開(kāi)銷(xiāo)和提升性能双炕,HTTP/2 使用 HPACK 壓縮格式壓縮請(qǐng)求和響應(yīng)標(biāo)頭元數(shù)據(jù),這種格式采用兩種簡(jiǎn)單但是強(qiáng)大的技術(shù):
- 這種格式支持通過(guò)靜態(tài) Huffman 代碼對(duì)傳輸?shù)臉?biāo)頭字段進(jìn)行編碼撮抓,從而減小了各個(gè)傳輸?shù)拇笮 ?/li>
- 這種格式要求客戶(hù)端和服務(wù)器同時(shí)維護(hù)和更新一個(gè)包含之前見(jiàn)過(guò)的標(biāo)頭字段的索引列表(換句話(huà)說(shuō)妇斤,它可以建立一個(gè)共享的壓縮上下文),此列表隨后會(huì)用作參考丹拯,對(duì)之前傳輸?shù)闹颠M(jìn)行有效編碼站超。
利用 Huffman 編碼,可以在傳輸時(shí)對(duì)各個(gè)值進(jìn)行壓縮乖酬,而利用之前傳輸值的索引列表死相,我們可以通過(guò)傳輸索引值的方式對(duì)重復(fù)值進(jìn)行編碼,索引值可用于有效查詢(xún)和重構(gòu)完整的標(biāo)頭鍵值對(duì)咬像。
HPACK 的安全性和性能
早期版本的 HTTP/2 和 SPDY 使用 zlib(帶有一個(gè)自定義字典)壓縮所有 HTTP 標(biāo)頭算撮。 這種方式可以將所傳輸標(biāo)頭數(shù)據(jù)的大小減小 85% - 88%生宛,顯著減少了頁(yè)面加載時(shí)間延遲:
在帶寬較低的 DSL 鏈路中,上行鏈路速度僅有 375 Kbps肮柜,僅壓縮請(qǐng)求標(biāo)頭就顯著減少了特定網(wǎng)站(即陷舅,發(fā)出大量資源請(qǐng)求的網(wǎng)站)的頁(yè)面加載時(shí)間。 我們發(fā)現(xiàn)素挽,僅僅由于標(biāo)頭壓縮蔑赘,頁(yè)面加載時(shí)間就減少了 45 - 1142 毫秒。(SPDY 白皮書(shū)预明,chromium.org)
然而缩赛,2012 年夏天,出現(xiàn)了針對(duì) TLS 和 SPDY 壓縮算法的“犯罪”安全攻擊撰糠,此攻擊會(huì)導(dǎo)致會(huì)話(huà)被劫持酥馍。 于是,zlib 壓縮算法被 HPACK 替代阅酪,后者經(jīng)過(guò)專(zhuān)門(mén)設(shè)計(jì)旨袒,可以解決發(fā)現(xiàn)的安全問(wèn)題、實(shí)現(xiàn)起來(lái)也更高效和簡(jiǎn)單术辐,當(dāng)然砚尽,可以對(duì) HTTP 標(biāo)頭元數(shù)據(jù)進(jìn)行良好壓縮。
參考文章:HTTP/2 簡(jiǎn)介