溫故知新,HTTP/2

去年年底昔逗,據(jù)國際互聯(lián)網(wǎng)工程任務(wù)組( IETF )消息,HTTP-over-QUIC 實驗性協(xié)議將被重命名為 HTTP/3篷朵,即有望成為 HTTP 協(xié)議的第三個正式版本勾怒,也就是說HTTP/3可能要來了。 該消息是如此的惹人注目声旺,是因為HTTP是我們身邊的協(xié)議笔链,Web應(yīng)用都離不開它。


信息公路

溫故知新腮猖,梳理一下過往鉴扫,或許更能夠理解未來。

HTTP1.x的過往

HTTP協(xié)議大約誕生在我上大一的時候澈缺,好像是HTTP0.9坪创,客戶端請求和服務(wù)器響應(yīng)都是ascii碼,客戶端以回車符結(jié)尾姐赡,服務(wù)器返回HTML莱预。后來的HTTP1.0,服務(wù)器響應(yīng)增加了很多狀態(tài)项滑,請求和響應(yīng)也多了很多的header依沮,響應(yīng)的內(nèi)容也不再局限于純文本了。

HTTP是一個應(yīng)用層協(xié)議枪狂,由請求和響應(yīng)構(gòu)成危喉,是一個標準的客戶端服務(wù)器模型,是一個無狀態(tài)的協(xié)議州疾。HTTP是建立在TCP之上的辜限,每個請求都要經(jīng)歷三次握手和慢啟動⊙媳停客戶端是依據(jù)域名來向服務(wù)器建立連接薄嫡,一般PC端的瀏覽器支持同域6~8個連接,手機端的連接數(shù)則一般控制在4~6個谈飒。連接數(shù)不是越多越好岂座,資源開銷和整體延遲都會隨之增大。

HTTP 1.1 導(dǎo)致了2000年的互聯(lián)網(wǎng)熱潮杭措。HTTP1.1 支持只發(fā)送header信息(不帶任何body信息)费什,如果服務(wù)器認為客戶端有權(quán)限請求服務(wù)器,則返回100,否則返回401鸳址〈耱剑客戶端如果接受到100,才開始把請求body發(fā)送到服務(wù)器稿黍。這樣當服務(wù)器返回401的時候疹瘦,客戶端就可以不用發(fā)送請求body了,節(jié)約了帶寬巡球。

另外HTTP還支持傳送內(nèi)容的一部分言沐。這樣當客戶端已經(jīng)有一部分的資源后,只需要跟服務(wù)器請求另外的部分資源即可酣栈。RANGE:bytes是HTTP/1.1新增內(nèi)容险胰,HTTP/1.0每次傳送文件都是從文件頭開始,即0字節(jié)處開始矿筝。RANGE:bytes=XXX表示要求服務(wù)器從文件XXX字節(jié)處開始傳送起便,這大概就是平時所說的斷點續(xù)傳。

相關(guān)的部分協(xié)議標準如下:

  • RFC7230 HTTP/1.1: Message Syntax and Routing 底層消息解析和連接管理等
  • RFC7231 HTTP/1.1: Semantics and Content 方法窖维、狀態(tài)碼和header等
  • RFC7232 HTTP/1.1: Conditional Requests 例如If-Modified-Since
  • RFC7233 HTTP/1.1: Range Requests 獲取部分內(nèi)容等
  • RFC7234 HTTP/1.1: Caching 瀏覽器和中介緩存等
  • RFC7235 HTTP/1.1: Authentication HTTP 的一個authentication框架等

現(xiàn)如今榆综,Web應(yīng)用不再單純是web 網(wǎng)頁,還有支持多設(shè)備和多媒體铸史。 一個SPA的應(yīng)用可能有上百的連接鼻疮,模塊拆分導(dǎo)致了更多的請求,大部分時間都消耗在網(wǎng)絡(luò)上沛贪。HTTP 1.x header 往往較大陋守,且無法壓縮震贵。TCP協(xié)議利用過低利赋,不可復(fù)用連接,連接數(shù)限制且協(xié)議過于龐大猩系。

HTTP1.x遇到的問題和解決方案

HTTP1.x主要存在連接無法復(fù)用和head of line blocking這兩個問題媚送。在第一個請求沒有收到回復(fù)之前,后續(xù)從應(yīng)用層發(fā)出的請求只能排隊寇甸。網(wǎng)絡(luò)通暢的時候性能影響不大塘偎,一旦第一個請求沒有抵達服務(wù)器,或者response因為網(wǎng)絡(luò)阻塞沒有及時返回拿霉,就會影響所有后續(xù)請求吟秩。

HTTP1.0協(xié)議頭里可以設(shè)置Connection:Keep-Alive。在header里設(shè)置Keep-Alive可以在一定時間內(nèi)復(fù)用連接绽淘,具體復(fù)用時間的長短可以由服務(wù)器控制涵防,一般在15秒左右,這與運營商蜂窩網(wǎng)絡(luò)的linger time相關(guān)沪铭。HTTP1.1之后Connection的默認值就是Keep-Alive壮池,如果要關(guān)閉連接復(fù)用需要顯式的設(shè)置Connection:Close偏瓤。這對PC端瀏覽器的體驗幫助很大,因為大部分的請求在集中在一小段時間以內(nèi)椰憋。但移動app的請求比較分散且時間跨度相對較大厅克,一般會從應(yīng)用層尋求其它解決方案,長連接方案或者偽長連接方案橙依。

為了解決HTTP連接復(fù)用证舟,可以采用長輪詢,HTTP streaming和websocket等方式窗骑。

和傳統(tǒng)的HTTP短鏈接相比褪储,長連接輪詢會在用戶增長的時候極大的增加服務(wù)器壓力。移動端網(wǎng)絡(luò)環(huán)境復(fù)雜慧域,像wifi和4g的網(wǎng)絡(luò)切換等鲤竹,這些場景都需要考慮重建連接。長輪詢方式穩(wěn)定性并不好昔榴,需要做好數(shù)據(jù)可靠性的保證辛藻,比如重發(fā)和ack機制。而且互订,response有可能會被中間代理cache住吱肌,要處理好業(yè)務(wù)數(shù)據(jù)的過期機制。

HTTP streaming是通過在server response的頭部里增加"Transfer Encoding: chunked"來告訴客戶端后續(xù)還會有新的數(shù)據(jù)仰禽。如果永遠不會結(jié)束氮墨,客戶端就會一直處于等待response的過程中。代理服務(wù)器會等待服務(wù)器的response結(jié)束之后才會將結(jié)果推送到請求客戶端吐葵。對于streaming這種業(yè)務(wù)數(shù)據(jù)無法按照請求來做分割规揪,所以客戶端每收到一塊數(shù)據(jù)都需要自己做協(xié)議解析。顯然這個數(shù)據(jù)通道也是單向的温峭,還有個缺陷就是不會產(chǎn)生重復(fù)的header數(shù)據(jù)猛铅。

websocket提供雙向的數(shù)據(jù)通道,優(yōu)勢在于提供了message的概念凤藏,比基于字節(jié)流的tcp socket使用更簡單奸忽,同時又提供了傳統(tǒng)的HTTP所缺少的長連接功能。但代價相對較高揖庄,基于tcp的socket編程技術(shù)難度相對復(fù)雜很多栗菜,而且需要自己制定協(xié)議。

HTTP/2 要點

HTTP2.0是以SPDY為原型進行討論和標準化的蹄梢,采用二進制格式傳輸數(shù)據(jù)疙筹,而非 HTTP/1.x 的文本格式。請求和響應(yīng)都統(tǒng)一為流,對消息頭采用 HPACK 進行壓縮傳輸腌歉,能夠節(jié)省消息頭占用的網(wǎng)絡(luò)的流量蛙酪。多路復(fù)用,就是所有的請求都是通過一個 TCP 連接并發(fā)完成翘盖,并支持Server Push和基于優(yōu)先級的流量控制桂塞。

HTTP/2 中的幀

幀(frame)是HTTP2中最小的通信單位,每個幀都會有幀header馍驯,每個幀用來承載HTTP header 或負荷數(shù)據(jù)阁危,或其他特定類型的幀。幀是遵循二進制編碼的汰瘫。幀格式如下:

length定義了整個幀的長度狂打,type定義幀主要有10種的類型:

  • 幀類型 code
  • DATA 0x0
  • HEADERS 0x1
  • PRIORITY 0x2
  • RSTSTREAM 0x3
  • PUSHPROMISE 0x4
  • SETTINGS 0x5
  • PING 0x6
  • GOAWAY 0x7
  • WINDOW_UPDATE 0x8
  • CONTINUATION 0x9

flags用位定義了一些重要的參數(shù),stream id用作流控制,而payload才是請求的正文混弥。

雖然協(xié)議的格式和HTTP1.x完全不同了趴乡,但并沒有改變HTTP1.x的語義,只是把原來HTTP1.x的header和body部分用frame重新封裝了一層而已蝗拿。調(diào)試的時候瀏覽器甚至?xí)袶TTP2.0的frame自動還原成HTTP1.x的格式晾捏。HTTP2.0與HTTP1.0的對比如下:

http2與1的對比

HTTP/2 中的header 壓縮

HTTP1.x的header由于cookie和user agent很容易變得較大,而且每次都要重復(fù)發(fā)送哀托。HTTP/2使用encoder來減少需要傳輸?shù)膆eader大小惦辛,通訊雙方各自cache一份header fields表,既避免了重復(fù)header的傳輸仓手,又減小了需要傳輸?shù)拇笮∨制搿8咝У膲嚎s算法可以很大的壓縮header拭荤,減少發(fā)送包的數(shù)量從而降低延遲截碴。

http/2頭壓縮

HTTP/2中的HPACK使用一份索引表來定義常用的 HTTP Header,保留原有的header list的順序,通過索引鍵值壓縮。 靜態(tài)表中包含了一些預(yù)定義的header字段傍衡,動態(tài)表默認是空的辛慰,會在頭部解壓縮的時候確定是否添加entry区匠「上瘢客戶端和服務(wù)器端使用header表來跟蹤和存儲之前發(fā)送的每一個鍵值對帅腌。在tcp連接期間,二者共同維護和更新麻汰。對于無法用索引替代的字符速客,有的會采用哈夫曼編碼壓縮。

HTTP/2 中的多路復(fù)用

把HTTP 消息分解為獨立的幀五鲫,交錯發(fā)送溺职,然后在另一端根據(jù)Stream ID 重新組裝是HTTP 2.0 最重要的一項增強。每個 Frame Header 都有一個 Stream ID。每次請求/響應(yīng)使用不同的 Stream ID浪耘。通過 Stream ID 標識乱灵,所有的請求和響應(yīng)都可以同時跑在一個TCP 連接上了。 下圖是 HTTP 和 spdy的并發(fā)模型對比:

http/2復(fù)用

和一般TCP連接釋放一樣七冲,如果客戶端沒有數(shù)據(jù)要請求痛倚,或服務(wù)端數(shù)據(jù)發(fā)送完畢后,會主動發(fā)送關(guān)閉連接的報文澜躺〔跷龋或者是服務(wù)端連續(xù)發(fā)送探測報文,客戶端無響應(yīng)掘鄙,服務(wù)端就關(guān)閉了這個連接耘戚。

當流并發(fā)時,就會涉及到流的優(yōu)先級和依賴操漠。優(yōu)先級高的流會被優(yōu)先發(fā)送收津。每個HTTP/2流里面可以帶有優(yōu)先級(31位,0為優(yōu)先級最高)的值浊伙,這個值確定著客戶端和服務(wù)器處理不同的流采取不同的優(yōu)先級策略朋截,高優(yōu)先級的流都應(yīng)該優(yōu)先發(fā)送。圖片請求的優(yōu)先級要低于CSS和SCRIPT腳本吧黄,這可以確保重要的東西可以被優(yōu)先加載部服。,但又不會絕對的拗慨,絕對地遵守可能又會引入隊列阻塞的問題:高優(yōu)先級的請求慢導(dǎo)致阻塞其他資源交付廓八。

從tcp連接和網(wǎng)絡(luò)來看,優(yōu)先級使得網(wǎng)絡(luò)擁塞得到改善赵抢,慢啟動時間減少剧蹂,擁塞和丟包恢復(fù)速度變快。

HTTP/2 中的Push

Server Push 就是服務(wù)器向客戶端推送資源而無需客戶端明確地請求烦却,或者服務(wù)器可以對一個客戶端請求發(fā)送多個響應(yīng)宠叼。

http/2推送

當服務(wù)端需要主動推送某個資源時,便會發(fā)送一個 Frame Type 為 PUSH_PROMISE 的 幀其爵,里面帶了 PUSH 需要新建的 Stream ID冒冬。客戶端解析 幀時摩渺,發(fā)現(xiàn)它是一個 PUSH_PROMISE 類型简烤,便會準備接收服務(wù)端要推送的流。

HTTP/2連接建立后摇幻,客戶端與服務(wù)器交換SETTINGS 幀横侦,以此來限定雙向并發(fā)流的最大數(shù)量挥萌。因此,客戶端可以限定推送流的數(shù)量枉侧,或者通過把這個值設(shè)置為0引瀑,完全禁用服務(wù)器推送,而且榨馁,所有推送的資源都遵守同源策略伤疙。服務(wù)器不能隨便將第三方資源推送給客戶端,而必須是經(jīng)過雙方確認才行辆影。

所有服務(wù)器推送流都由PUSH_PROMISE 發(fā)起徒像,PUSH_PROMISE 幀必須在返回響應(yīng)之前發(fā)送,以免客戶端出現(xiàn)競態(tài)條件蛙讥【庵客戶端接收到PUSH_PROMISE 幀之后,可以視自身需求選擇拒絕這個流次慢。

基于HTTP/2的開發(fā)

HTTP/2 已經(jīng)得到了較為廣泛的支持旁涤,服務(wù)器的支持包括:

  • Apache HTTP Server 2.4.17+
  • Apache Tomcat 8.5+
  • NGINX 1.9.5+
  • 面向PHP的Swoole
  • 面向Python 的Twisted
  • ...

支持HTTP/2的客戶端包括:

  • Chromium
  • Mozilla Firefox
  • curl and libcurl
  • OkHTTP (java ,Android)
  • 面向Obj-C/swift 的 WKWebView
  • ...

客戶端與服務(wù)器同時支持HTTP/2的包括:

  • Jetty/Netty
  • lua-HTTP
  • Node.js 8.4.0+
  • 面向perl 的 Protocol::HTTP2
  • 面向Go 的HTTP2
  • ...

支持HTTP/2的代理中介包括:

  • HAProxy
  • ngHTTP2
  • GFE
  • ...

詳情可以參考HTTPs://github.com/HTTP2/HTTP2-spec/wiki/Implementations迫像。

調(diào)試工具可以使用chrome的瀏覽器以及Wireshark等等劈愚。

http/2與http1x的性能對比

在開發(fā)中使用了HTTP/2 并不是萬事大吉了,在HTTP1.X 中的一些優(yōu)化還需要繼續(xù)使用闻妓,例如減少DNS查詢和重定向菌羽,CDN的使用,對代碼由缆、圖片等資源的壓縮注祖,對文本開啟GZip,以及使用HTTP的緩存機制(Expires/Cache-Control和Last-Modified / ETag)等等均唉。對于那些可以感知緩存的資源內(nèi)聯(lián)或者Push 消息是晨,可以利用cookie 協(xié)助用戶標記。

由于HTTP/2基于單個TCP連接舔箭,容易受到 Head of Line Blocking 的影響罩缴,從而導(dǎo)致傳輸速度受限,還會受到TCP丟包的影響层扶,所以HTTP/2在資源數(shù)量較少的網(wǎng)站可能效果不明顯箫章。TCP協(xié)議的升級依賴于操作系統(tǒng)內(nèi)核的升級,尤其是網(wǎng)絡(luò)操作系統(tǒng)的升級往往不可控怒医,因此業(yè)界開始重新審視UDP炉抒, HTTP/3 所使用的QUIC 就是基于UDP協(xié)議的。

HTTP/3 何時才能實施呢稚叹?整個互聯(lián)網(wǎng)支持HTTP/3 可能還需要一段不短的時間吧焰薄!
(更多內(nèi)容,請關(guān)注公眾號:wireless_com)
參考資料:

*《HTTP 權(quán)威指南》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扒袖,一起剝皮案震驚了整個濱河市塞茅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌季率,老刑警劉巖野瘦,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異飒泻,居然都是意外死亡鞭光,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門泞遗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惰许,“玉大人,你說我怎么就攤上這事史辙⌒诼颍” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵聊倔,是天一觀的道長晦毙。 經(jīng)常有香客問我,道長耙蔑,這世上最難降的妖魔是什么见妒? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮甸陌,結(jié)果婚禮上徐鹤,老公的妹妹穿的比我還像新娘。我一直安慰自己邀层,他們只是感情好返敬,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寥院,像睡著了一般劲赠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秸谢,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天凛澎,我揣著相機與錄音,去河邊找鬼估蹄。 笑死塑煎,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的臭蚁。 我是一名探鬼主播最铁,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼讯赏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了冷尉?” 一聲冷哼從身側(cè)響起漱挎,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎雀哨,沒想到半個月后磕谅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡雾棺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年膊夹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捌浩。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡放刨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嘉栓,到底是詐尸還是另有隱情宏榕,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布侵佃,位于F島的核電站麻昼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏馋辈。R本人自食惡果不足惜抚芦,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迈螟。 院中可真熱鬧叉抡,春花似錦、人聲如沸答毫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽洗搂。三九已至消返,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間耘拇,已是汗流浹背撵颊。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惫叛,地道東北人倡勇。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像嘉涌,于是被迫代替她去往敵國和親妻熊。 傳聞我的和親對象是個殘疾皇子夸浅,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容