HTTP/2,也就是超文本傳輸協議第2版,不論是1還是2,HTTP的基本語義是不變的,比如方法語義(GET/PUST/PUT/DELETE),狀態碼(200/404/500等),Range Request,Cacheing,Authentication、URL路徑, 不同的主要是下面幾點:
HTTP2 主要是針對 Http1的下面幾個問題做的優化:
- 並行能力有限
- 客戶端請求隊列
- 較高的協議負載
每一個源最大只支持6個請求
管道在實際使用時不起作用
競爭性的TCP流,強制快速重傳(Spurious retransmissions)
額外的握手、內存緩沖等
隊首阻塞
延遲的請求分發
頭信息和Cookies大約要800字節
HTTP元數據沒有壓縮
另外,HTTP/1.1只允許由客戶端主動發起請求,服務端只能等待客戶端發送請求,這對於滿足預加載的現狀是一種桎梏。
http://www.infoq.com/cn/news/2014/11/http2-develop
http2是一個二進制協議。
HTTP/2 傳輸的數據是二進制的。相比 HTTP/1.1 的純文本數據,二進制數據一個顯而易見的好處是:更小的傳輸體積。這就意味着更低的負載。二進制的幀也更易於解析而且不易出錯,純文本幀在解析的時候還要考慮處理空格、大小寫、空行和換行等問題,而二進制幀就不存在這個問題。
在 HTTP/2 的語境下,有三個概念需要厘清,它們就是:流(Stream)、消息(Message) 和幀(Frame)。
Stream 處於一個連接中的雙向二進制數據流,可以包含一個或者多個 Message。
Message 一個完整的請求或者響應,包含多個 Frame 序列。
Frame HTTP/2 通訊中的最小傳輸單位,至少含有一個 Frame header,能夠表示它屬於哪一個 Stream。
如下圖所示:
幀(Frame)的類型有很多種,但他們都有如下的公共字段:
Type, Length, Flags, Steam Identifier和frame payload
一個具體請求的HTTP2類似如下圖:
多路復用的流
每個http2連接上傳輸的幀都關聯到一個“流”。流是一個邏輯上的結合,一個獨立的,雙向的幀序列。它在客戶端和服務器端中間通過http2連接進行幀交換。
每個單獨的http2連接都可以包含多個並發的流,任何一端都可以交錯地插入幀。流既可以被客戶端/服務器端單方面的建立、使用,也可以被雙方共享。同時,兩邊都可以關閉流。
流的多路復用意味着在同一連接中來自各個流的數據包被混合在一起。兩個(或者更多)獨立的“數據列車”被拼湊到了一輛列車上,最終在終點站被分開。下面就是兩列“數據火車”:
它們就是這樣通過多路復用的方式被組裝到了同一列火車上。
在http2里面,我們很容易可以看到10個甚至100個同時並存的流。創建一個新的流的代價也非常低。
它允許多個並發 HTTP 請求共用一個 TCP會話,而不是為每個請求單獨開放連接,這樣只需建立一個 TCP 連接就可以傳送網頁上所有資源,不僅可以減少消息交互往返的時間還可以避免創建新連接造成的延遲,使得 TCP 的效率更高。
HTTP1.x上如果一個只用一個持久鏈接,請求只能一個一個順序請求,為了高效地並行下載資源,瀏覽器允許我們打開多個TCP會話,但是一個域名下限制6個鏈接,如下。
優先級和依賴關系
每個流都包含一個優先級,優先級被用來告訴對端哪個流更重要。
優先級能動態的被改變,這可以讓用戶滾動一個全是圖片的頁面的時候,瀏覽器可以指定哪個圖片有更高的優先級。或者是在你切換標簽頁的時候,瀏覽器可以提升新切換到頁面所包含流的優先級。
參考: http://segmentfault.com/a/1190000002718083
http://segmentfault.com/a/1190000002642924
頭壓縮
HTTP是無狀態協議。簡而言之,這意味着每個請求必須要攜帶服務器需要的所有細節,而不是讓服務器保存住之前請求的元數據。因為http2沒有改變這個范式,所以它也需要這樣(攜帶所有細節),因此 HTTP 請求的頭部需要包含用於標識身份的數據比如 cookies
,而這些數據的量也在隨着時間增長。每一個請求的頭部都包含這些大量的重復數據,無疑是一種很大的負擔。對請求頭部進行壓縮,將會大大減輕這種負擔,尤其對移動端來說,性能提高非常明顯。
HTTP/2 使用的壓縮方式是 HPACK。 http://http2.github.io/http2-spec/compression.html
HTTP2.0在客戶端和服務器端使用“首部表”來跟蹤和存儲之前發送的鍵-值對,對於相同的數據,不再通過每次請求和響應發送;通信期間幾乎不會改變的通用鍵-值對(用戶代理、可接受的媒體類型,等等)只需發送一次。
事實上,如果請求中不包含首部(例如對同一資源的輪詢請求),那么首部開銷就是零字節。此時所有首部都自動使用之前請求發送的首部。
如果首部發生變化了,那么只需要發送變化了數據在Headers幀里面,新增或修改的首部幀會被追加到“首部表”。首部表在 HTTP2.0的連接存續期內始終存在,由客戶端和服務器共同漸進地更新。
http://liyaoli.com/2015-04-18/HTTP-2.0.html
重置-后悔葯
Length的HTTP消息被送出之后,我們就很難中斷它了。當然,通常我們可以斷開整個TCP鏈接(但也不總是可以這樣),但這樣導致的代價就是需要重新通過三次握手建立一個新的TCP連接。
HTTP/2 引入了一個 RST_STREAM frame 來讓客戶端在已有的連接中發送重置請求,從而中斷或者放棄響應。當瀏覽器進行頁面跳轉或者用戶取消下載時,它可以防止建立新連接,避免浪費所有帶寬。
服務器推送
HTTP/2 的服務器推送所作的工作就是,服務器在收到客戶端對某個資源的請求時,會判斷客戶端十有八九還要請求其他的什么資源,然后一同把這些資源都發送給客戶端,即便客戶端還沒有明確表示它需要這些資源。
客戶端可以選擇把額外的資源放入緩存中(所以這個特點也叫 Cache push),也可以選擇發送一個 RST_STREAM frame 拒絕任何它不想要的資源。
流量控制
幀類型決定了是否適用流量控制規則。只有DATA幀受流量控制;其他類型的幀不受流量控制。
有些瀏覽器希望事先知道圖片顯示尺寸,可用更好的做布局,減少reflow現象,如果可以預先下載圖片的元數據(圖片頭內有)就太好了, 用這個技術就可以先發前面的~kb
。
http://segmentfault.com/a/1190000002676016
備選服務
隨着http2逐漸被接受,我們有理由猜測,相對於HTTP 1.x,TCP連接會更長且被保持的更久。客戶端到每個主機/站點的每一條連接都可以做盡可能多的事情,因此每個連接也可能被保持開啟更長的時間。
這會影響到HTTP負載均衡器的正常工作,也可能在一個網站想建議客戶端連接到另外一個主機的時候引起問題。通常,網站此舉的目的在照顧性能,也可能是正常維護或類似原因。
服務器將會通過發送Alt-Svc頭(或者http2的ALTSVC幀)通知客戶端另一個備選服務。即另外一條獲取同樣內容的路由,但它指向不同的服務源、主機或端口。
客戶端可以嘗試異步的連接到服務,或者可能的話,使用備選服務。
http://ye11ow.gitbooks.io/http2-explained/content/07_extensions.html
參考資料:
HTTP2講解
http://ye11ow.gitbooks.io/http2-explained/content/
http://hackll.com/2015/04/25/introduce-http2/
http://www.infoq.com/cn/news/2014/02/http-2
http://www.w3ctech.com/topic/862
http://www.alloyteam.com/2015/03/http2-0-di-qi-miao-ri-chang/