HTTP1.0
1、任何格式的內(nèi)容都可以發(fā)送存谎。這使得互聯(lián)網(wǎng)不僅可以傳輸文字拔疚,還能傳輸圖像、視頻既荚、二進制文件稚失。這為互聯(lián)網(wǎng)的大發(fā)展奠定了基礎(chǔ)。
2恰聘、除了GET命令句各,還引入了POST命令和HEAD命令,豐富了瀏覽器與服務(wù)器的互動手段晴叨。
3凿宾、HTTP請求和回應(yīng)的格式也變了。除了數(shù)據(jù)部分兼蕊,每次通信都必須包括頭信息(HTTP header)初厚,用來描述一些元數(shù)據(jù)。
4孙技、其他的新增功能還包括狀態(tài)碼(status code)产禾、多字符集支持、多部分發(fā)送(multi-part type)牵啦、權(quán)限(authorization)亚情、緩存(cache)、內(nèi)容編碼(content encoding)等哈雏。
但是每個TCP連接只能發(fā)送一個請求楞件。發(fā)送數(shù)據(jù)完畢,連接就關(guān)閉裳瘪,如果還要請求其他資源土浸,就必須再新建一個連接。TCP連接的新建成本很高盹愚,因為需要客戶端和服務(wù)器三次握手栅迄,并且開始時發(fā)送速率較慢(slow start)。所以皆怕,HTTP 1.0版本的性能比較差毅舆。隨著網(wǎng)頁加載的外部資源越來越多西篓,這個問題就愈發(fā)突出了。
HTTP1.1
1憋活、引入了持久連接(persistent connection)岂津,即TCP連接默認不關(guān)閉,可以被多個請求復(fù)用悦即,不用聲明Connection: keep-alive吮成。客戶端和服務(wù)器發(fā)現(xiàn)對方一段時間沒有活動辜梳,就可以主動關(guān)閉連接粱甫。不過,規(guī)范的做法是作瞄,客戶端在最后一個請求時茶宵,發(fā)送Connection: close,明確要求服務(wù)器關(guān)閉TCP連接
2宗挥、引入了管道機制(pipelining)乌庶,即在同一個TCP連接里面,客戶端可以同時發(fā)送多個請求契耿。這樣就進一步改進了HTTP協(xié)議的效率瞒大。舉例來說,客戶端需要請求兩個資源搪桂。以前的做法是透敌,在同一個TCP連接里面,先發(fā)送A請求锅棕,然后等待服務(wù)器做出回應(yīng)拙泽,收到后再發(fā)出B請求淌山。管道機制則是允許瀏覽器同時發(fā)出A請求和B請求裸燎,但是服務(wù)器還是按照順序,先回應(yīng)A請求泼疑,完成后再回應(yīng)B請求德绿。
3、將Content-length字段的作用進行擴充退渗,即聲明本次回應(yīng)的數(shù)據(jù)長度(一個TCP連接現(xiàn)在可以傳送多個回應(yīng)移稳,勢必就要有一種機制,區(qū)分?jǐn)?shù)據(jù)包是屬于哪一個回應(yīng)的)
4会油、采用分塊傳輸編碼个粱,對于一些很耗時的動態(tài)操作,服務(wù)器需要等到所有操作完成翻翩,才能發(fā)送數(shù)據(jù)都许,顯然這樣的效率不高稻薇。更好的處理方法是,產(chǎn)生一塊數(shù)據(jù)胶征,就發(fā)送一塊塞椎,采用"流模式"(stream)取代"緩存模式"(buffer)
5、1.1版還新增了許多動詞方法:PUT睛低、PATCH案狠、HEAD、 OPTIONS钱雷、DELETE骂铁。另外,客戶端請求的頭信息新增了Host字段罩抗,用來指定服務(wù)器的域名从铲。
雖然1.1版允許復(fù)用TCP連接,但是同一個TCP連接里面澄暮,所有的數(shù)據(jù)通信是按次序進行的名段。服務(wù)器只有處理完一個回應(yīng),才會進行下一個回應(yīng)泣懊。要是前面的回應(yīng)特別慢伸辟,后面就會有許多請求排隊等著。這稱為"隊頭堵塞"(Head-of-line blocking)馍刮。為了避免這個問題信夫,只有兩種方法:一是減少請求數(shù),二是同時多開持久連接卡啰。這導(dǎo)致了很多的網(wǎng)頁優(yōu)化技巧静稻,比如合并腳本和樣式表、將圖片嵌入CSS代碼匈辱、域名分片(domain sharding)等等振湾。如果HTTP協(xié)議設(shè)計得更好一些,這些額外的工作是可以避免的亡脸。
HTTP2.0
首先附上一個鏈接來體驗http2.0的速度
HTTP1.x有以下幾個主要缺點:
HTTP/1.0一次只允許在一個TCP連接上發(fā)起一個請求押搪,HTTP/1.1使用的流水線技術(shù)也只能部分處理請求并發(fā),仍然會存在隊列頭阻塞問題浅碾,因此客戶端在需要發(fā)起多次請求時大州,通常會采用建立多連接來減少延遲。
單向請求垂谢,只能由客戶端發(fā)起厦画。
請求報文與響應(yīng)報文首部信息冗余量大。
數(shù)據(jù)未壓縮滥朱,導(dǎo)致數(shù)據(jù)的傳輸量大根暑。
二進制傳輸
http1.x誕生的時候是明文協(xié)議娃豹,其格式由三部分組成:start line(request line或者status line),header购裙,body懂版。要識別這3部分就要做協(xié)議解析,http1.x的解析是基于文本躏率∏耄基于文本協(xié)議的格式解析存在天然缺陷,文本的表現(xiàn)形式有多樣性薇芝,要做到健壯性考慮的場景必然很多蓬抄,二進制則不同,只認0和1的組合夯到∪络裕基于這種考慮http2.0的協(xié)議解析決定采用二進制格式,實現(xiàn)方便且健壯耍贾。
http2.0的格式定義更接近tcp層的方式阅爽,這張二機制的方式十分高效且精簡。length定義了整個frame的開始到結(jié)束荐开,type定義frame的類型(一共10種)付翁,flags用bit位定義一些重要的參數(shù),stream id用作流控制晃听,剩下的payload就是request的正文了百侧。
雖然看上去協(xié)議的格式和http1.x完全不同了,實際上http2.0并沒有改變http1.x的語義能扒,只是把原來http1.x的header和body部分用frame重新封裝了一層而已佣渴。調(diào)試的時候瀏覽器甚至?xí)裩ttp2.0的frame自動還原成http1.x的格式。具體的協(xié)議關(guān)系可以用下圖表示:
連接共享
http2.0要解決的一大難題就是多路復(fù)用(MultiPlexing)初斑,即連接共享辛润。上面協(xié)議解析中提到的stream id就是用作連接共享機制的。一個request對應(yīng)一個stream并分配一個id越平,這樣一個連接上可以有多個stream频蛔,每個stream的frame可以隨機的混雜在一起灵迫,接收方可以根據(jù)stream id將frame再歸屬到各自不同的request里面秦叛。
前面還提到過連接共享之后,需要優(yōu)先級和請求依賴的機制配合才能解決關(guān)鍵請求被阻塞的問題瀑粥。http2.0里的每個stream都可以設(shè)置又優(yōu)先級(Priority)和依賴(Dependency)挣跋。優(yōu)先級高的stream會被server優(yōu)先處理和返回給客戶端,stream還可以依賴其它的sub streams狞换。優(yōu)先級和依賴都是可以動態(tài)調(diào)整的避咆。動態(tài)調(diào)整在有些場景下很有用舟肉,假想用戶在用你的app瀏覽商品的時候,快速的滑動到了商品列表的底部查库,但前面的請求先發(fā)出路媚,如果不把后面的請求優(yōu)先級設(shè)高,用戶當(dāng)前瀏覽的圖片要到最后才能下載完成樊销,顯然體驗沒有設(shè)置優(yōu)先級好整慎。同理依賴在有些場景下也有妙用。
header壓縮
在HTTP1.0中围苫,我們使用文本的形式傳輸header裤园,在header中攜帶cookie的話,每次都需要重復(fù)傳輸幾百到幾千的字節(jié)剂府,這著實是一筆不小的開銷拧揽。
在HTTP2.0中,我們使用了HPACK(HTTP2頭部壓縮算法)壓縮格式對傳輸?shù)膆eader進行編碼腺占,減少了header的大小淤袜。并在兩端維護了索引表,用于記錄出現(xiàn)過的header衰伯,后面在傳輸過程中就可以傳輸已經(jīng)記錄過的header的鍵名饮怯,對端收到數(shù)據(jù)后就可以通過鍵名找到對應(yīng)的值。
壓縮算法的選擇
SPDY/2使用的是gzip壓縮算法嚎研,但后來出現(xiàn)的兩種攻擊方式BREACH和CRIME使得即使走ssl的SPDY也可以被破解內(nèi)容蓖墅,最后綜合考慮采用的是一種叫HPACK的壓縮算法。這兩個漏洞和相關(guān)算法可以點擊鏈接查看更多的細節(jié)临扮,不過這種漏洞主要存在于瀏覽器端论矾,因為需要通過javascript來注入內(nèi)容并觀察payload的變化。
重置連接表現(xiàn)更好
很多app客戶端都有取消圖片下載的功能場景杆勇,對于http1.x來說贪壳,是通過設(shè)置tcp segment里的reset flag來通知對端關(guān)閉連接的。這種方式會直接斷開連接蚜退,下次再發(fā)請求就必須重新建立連接闰靴。http2.0引入RST_STREAM類型的frame,可以在不斷開連接的前提下取消某個request的stream钻注,表現(xiàn)更好蚂且。
Server Push
在HTTP2.0中,服務(wù)端可以在客戶端某個請求后幅恋,主動推送其他資源杏死。
可以想象一下,某些資源客戶端是一定會請求的,這時就可以采取服務(wù)端push的技術(shù)淑翼,提前給客戶端推送必要的資源腐巢,就可以相對減少一點延遲時間。在瀏覽器兼容的情況下也可以使用prefetch玄括。
Server Push的功能前面已經(jīng)提到過冯丙,http2.0能通過push的方式將客戶端需要的內(nèi)容預(yù)先推送過去,所以也叫“cache push”遭京。另外有一點值得注意的是银还,客戶端如果退出某個業(yè)務(wù)場景,出于流量或者其它因素需要取消server push洁墙,也可以通過發(fā)送RST_STREAM類型的frame來做到蛹疯。
流量控制(Flow Control)
TCP協(xié)議通過sliding window的算法來做流量控制。發(fā)送方有個sending window热监,接收方有receive window捺弦。http2.0的flow control是類似receive window的做法,數(shù)據(jù)的接收方通過告知對方自己的flow window大小表明自己還能接收多少數(shù)據(jù)孝扛。只有Data類型的frame才有flow control的功能列吼。對于flow control,如果接收方在flow window為零的情況下依然更多的frame苦始,則會返回block類型的frame寞钥,這張場景一般表明http2.0的部署出了問題。