HTTP/2是一個二進制協議,其基於「幀」的結構設計,改進了不少HTTP/1.1痛點問題。下面列舉一些最常被津津樂道的改進之處:css
以上列舉的每一項都值得作深刻細緻的研究,這裏就只針對「多路複用」功能的實現進行深刻的學習。html
網絡上有一張圖能清晰的解釋這個問題:
HTTP/1.1協議的請求-響應模型你們都是熟悉的,咱們用「HTTP消息」來表示一個請求-響應的過程,那麼HTTP/1.1中的消息是「管道串形化」的:只有等一個消息完成以後,才能進行下一條消息;而HTTP/2中多個消息交織在了一塊兒,這無疑提升了「通訊」的效率。這就是多路複用:在一個HTTP的鏈接上,多路「HTTP消息」同時工做。前端
簡單回答就是:HTTP/2是基於二進制「幀」的協議,HTTP/1.1是基於「文本分割」解析的協議。
看一個HTTP/1.1簡單的GET請求例子:web
GET / HTTP/1.1 Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.9,en;q=0.8 Cache-Control:max-age=0 Connection:keep-alive Cookie:imooc_uuid=b2076a1d-6a14-4cd5-91b0-17a9a2461cf4; imooc_isnew_ct=1517447702; imooc_isnew=2; zg_did=%7B%22did%22%3A%20%221662d799f3f17d-0afe8166871b85-454c092b-100200-1662d799f4015b%22%7D; loginstate=1; apsid=Y4ZmEwNGY3OTUwMTdjZTk0ZTc4YzBmYThmMDBmZDYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANDEwNzI4OQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5NTMzNjIzNjVAcXEuY29tAAAAAAAAAAAAAAAAAAAAADBmNmM5MzczZTVjMTk3Y2VhMDE2ZjUxNmQ0NDUwY2IxIDPdWyAz3Vs%3DYj; Hm_lvt_fb538fdd5bd62072b6a984ddbc658a16=1541222935,1541224845; Hm_lvt_f0cfcccd7b1393990c78efdeebff3968=1540010199,1541222930,1541234759; zg_f375fe2f71e542a4b890d9a620f9fb32=%7B%22sid%22%3A%201541297212384%2C%22updated%22%3A%201541297753524%2C%22info%22%3A%201541222929083%2C%22superProperty%22%3A%20%22%7B%5C%22%E5%BA%94%E7%94%A8%E5%90%8D%E7%A7%B0%5C%22%3A%20%5C%22%E6%85%95%E8%AF%BE%E7%BD%91%E6%95%B0%E6%8D%AE%E7%BB%9F%E8%AE%A1%5C%22%2C%5C%22%E5%B9%B3%E5%8F%B0%5C%22%3A%20%5C%22web%5C%22%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%22Jph3DQ809OQ%2C%22%7D; PHPSESSID=h5jn68k1fcaadn61bpoqa9hch2; cvde=5be7a057c314b-1; IMCDNS=1 Host:www.imooc.com Referer:https://www.imooc.com/ Upgrade-Insecure-Requests:1 User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
以上就是HTTP/1.1發送請求消息的文本格式:以換行符分割每一條key:value的內容,解析這種數據用不着什麼高科技,相反的,解析這種數據每每速度慢且容易出錯。「服務端」須要不斷的讀入字節,直到遇到分隔符(這裏指換行符,代碼中可能使用/n或者/r/n表示),這種解析方式是可行的,而且HTTP/1.1已經被普遍使用了二十多年,這事已經作過無數次了,問題一直都是存在的:算法
前邊提到:HTTP/2設計是基於「二進制幀」進行設計的,這種設計無疑是一種「高超的藝術」,由於它實現了一個目的:一切可預知,一切可控。
幀是一個數據單元,實現了對消息的封裝。下面是HTTP/2的幀結構:
幀的字節中保存了不一樣的信息,前9個字節對於每一個幀都是一致的,「服務器」解析HTTP/2的數據幀時只須要解析這些字節,就能準確的知道整個幀指望多少字節數來進行處理信息。咱們先來了解一下幀中每一個字段保存的信息:瀏覽器
名稱 | 長度 | 描述 |
---|---|---|
Length | 3 字節 | 表示幀負載的長度,默認最大幀大小2^14 |
Type | 1 字節 | 當前幀的類型,下面會作介紹 |
Flags | 1 字節 | 具體幀的標識 |
R | 1 字節 | 保留位,不須要設置,不然可能帶來嚴重後果 |
Stream Identifier | 31 位 | 每一個流的惟一ID |
Frame Payload | 不固定 | 真實幀的長度,真實長度在Length中設置 |
若是使用HTTP/1.1的話,你須要發送完上一個請求,才能發送下一個;因爲HTTP/2是分幀的,請求和響應能夠交錯甚至能夠複用。
爲了可以發送不一樣的「數據信息」,經過幀數據傳遞不一樣的內容,HTTP/2中定義了10種不一樣類型的幀,在上面表格的Type字段中可對「幀」類型進行設置。下表是HTTP/2的幀類型:緩存
名稱 | ID | 描述 |
---|---|---|
DATA | 0x0 | 傳輸流的核心內容 |
HEADERS | 0x1 | 包含HTTP首部,和可選的優先級參數 |
PRIORITY | 0x2 | 指示或者更改流的優先級和依賴 |
RST_STREAM | 0x3 | 容許一端中止流(一般是因爲錯誤致使的) |
SETTINGS | 0x4 | 協商鏈接級參數 |
PUSH_PROMISE | 0x5 | 提示客戶端,服務端要推送些東西 |
PING | 0x6 | 測試鏈接可用性和往返時延(RTT) |
GOAWAY | 0x7 | 告訴另一端,當前端已結束 |
WINDOW_UPDATE | 0x8 | 協商一端要接收多少字節(用於流量控制) |
CONTINUATION | 0x9 | 用以拓展HEADER數據塊 |
有了以上對HTTP/2幀的瞭解,咱們就能夠解釋多路複用是怎樣實現的了,不過在這以前咱們先來了解「流」的概念:HTTP/2鏈接上獨立的、雙向的幀序列交換。流ID(幀首部的6-9字節)用來標識幀所屬的流
下面兩張圖分別表示了HTTP/2協議上POST請求數據流「複用」的過程,很容易看的明白:
服務器
因爲HTTP/2消息中「幀」的設計,客戶端和服務端在通訊的過程當中可以彼此瞭解更多的信息。下面再簡單說一下其餘幾點比較重要的特性,算是一個學習引導方向吧。網絡
HTTP/2的新特性之一是基於流的流量控制。不一樣於HTTP/1.1,只要客戶端能夠處理,服務端就會盡量快的發送數據,HTTP/2提供了客戶端調整傳輸速度的能力(服務端也能夠)。WINDOW_UPDATE幀用來完成這件事情,每一個幀告訴對方,發送方想要接收多少字節,它將發送一個WINDOW_UPDATE幀以指示其更新後的處理字節能力。app
流的一個重要特性是能夠設置優先級和資源數據的依賴關係。HTTP/2經過流的依賴能夠實現這些功能。經過HEADERS幀和PRIORITY幀,客戶端能夠明確的告訴服務端它最須要什麼,這是經過聲明依賴關係和權重實現的。
《孫子兵法》中有一句名言:「兵馬未到,糧草先行」。服務端推送功能就能夠實現這樣一個功能。當頁面尚未開始請求具體的資源時,服務端就已經把一些資源(像css和js)已經推送到客戶端了。當瀏覽器要渲染頁面時,資源已經在緩存中了,聽起來是一件很酷的事情,實際上也正是這樣。服務端推送是經過PUSH_PROMISE幀實現的,固然其實現的細節是很是複雜的,感興趣的同窗能夠研究一下。HTTP/2的「多路複用」問題已經說明白了,還補充了一些新特性的介紹。固然想要深刻了解HTTP/2的一些原理,有太多太多的內容須要閱讀,實踐。好比「首部壓縮」算法HPACK是HTTP/2的關鍵元素之一,是HTTP/2制定開發組長時間的研究成果,其思想內容也是特別值得學習借鑑的。本節所設計到的東西只是HTTP/2協議中的冰山一角,RFC7540能夠幫助你充分了解該協議的方方面面。