HTTP/2主要通過以下方法減少延遲,改進頁面的加載速度:
- HTTP Header的壓縮,采用HPack算法。
- HTTP/2的Server Push。
- 請求的pipeline。
- 修復在HTTP 1.x的隊頭阻塞問題。
- 在單個TCP連接里多工復用請求。
HTTP/2 頭部壓縮(HPack)
使用HPack算法壓縮HTTP/2的頭部,下面簡單介紹Hpack的工作原理:

簡單說,HTTP頭壓縮需要在HTTP/2客戶端和服務端之間:
- 維護一份相同的靜態(tài)表(Static Table),包含常見的頭部名稱,和其鍵值對;
- 維護一份相同的動態(tài)表(Dynamic Table),可以動態(tài)地添加內容;
- 基于靜態(tài)哈夫曼碼表的哈夫曼編碼(Huffman Coding);
比如,在HTTP頭里,有些key:value是固定的:
:method: GET
:scheme: http
在編碼時,它們直接用一個index編號代替,例如:method:GET是2,這些在一個靜態(tài)表定義。靜態(tài)表的定義如下,總共61個Header Name,點擊URL https://tools.ietf.org/html/rfc7541#appendix-A查看所有靜態(tài)表的定義。
列出定義的部分鍵值對:
| Index | Header Name | Header Value |
|---|---|---|
| 1 | :authority | |
| 2 | :method | GET |
| 3 | :method | POST |
| 4 | :path | / |
| 5 | :path | /index.html |
| 6 | :scheme | http |
| 7 | :scheme | https |
| 8 | :status | 200 |
| ... | ... | ... |
| 32 | cookie | |
| ... | ... | ... |
| 60 | via | |
| 61 | www-authenticate |
使用靜態(tài)表、動態(tài)表、以及Huffman編碼可以極大地提升壓縮效果。對于靜態(tài)表里的字段,原來需要N個字符表示的,現(xiàn)在只需要一個索引即可。對于靜態(tài)、動態(tài)表中不存在的內容,還可以使用哈夫曼編碼來減小體積。
HTTP/2的多路復用
HTTP/2定義了流(Stream)和幀(Frame)?;緟f(xié)議單元變小了,從消息(Message)變成了幀;流作為一種虛擬的通道,用來傳輸幀。與創(chuàng)建TCP連接相比,創(chuàng)建流的成本幾乎為零。基本協(xié)議單元的變小也大大提高了連接的利用效率。
HTTP 1.1 默認啟用長TCP連接,但所有的請求-響應都是按序進行的(這里的長連接可理解成半雙工協(xié)議。即便是HTTP 1.1引入了管道機制,也是如此)。復用同一個TCP連接期間,即便是通過管道同時發(fā)送了多個請求,服務端也是按請求的順序依次給出響應的;而客戶端在未收到之前所發(fā)出所有請求的響應之前,將會阻塞后面的請求(排隊等待),這稱為"隊頭堵塞"(Head-of-line blocking)。
HTTP/2復用TCP連接則不同,雖然依然遵循請求-響應模式,但客戶端發(fā)送多個請求和服務端給出多個響應的順序不受限制,這樣既避免了"隊頭堵塞",又能更快獲取響應。在復用同一個TCP連接時,服務器同時(或先后)收到了A、B兩個請求,先回應A請求,但由于處理過程非常耗時,于是就發(fā)送A請求已經處理好的部分, 接著回應B請求,完成后,再發(fā)送A請求剩下的部分。HTTP/2長連接可以理解成全雙工的協(xié)議。
一幅圖了解上面的描述:

HTTP/2的Server Push
HTTP/2與HTTP/1最大的不同之處在于,前者在后者的基礎上定義了流和幀,實現(xiàn)了多路復用。這是Server Push的基礎。
在HTTP 1.1里,在同一個 TCP 連接里面,上一個回應(response)發(fā)送完了,服務器才能發(fā)送下一個,但在HTTP/2里,可以將多個回應一起發(fā)送。

下圖是PUSH模式,當請求一個HTML時,如果HTML里有CSS文件,server會一并推給client,而不像在HTTP 1.1下,還需要再發(fā)一個CSS的請求。

根據(jù)上圖,從理論上PUSH模式下性能會好很多。
舉個例子解釋一下。下面是一個簡單的HTML頁面,假說是index.html 。
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<p>This is a sample to illustrate how HTTP/2 works</p>
<img src="example.png">
</body>
</html>
這里有三個文件需要處理:該HTML頁面、CSS文件style.css以及圖片example.png。在HTTP 1.1里為了處理這三個文件,Client需要發(fā)三個請求給Server。
首先,發(fā)送一個請求index.html。
GET /index.html HTTP/1.1
Client解析該HTML文件,繼而知道有2個style.css和example.png資源文件下載。
Client繼續(xù)發(fā)送2個請求下載他們。
GET /style.css HTTP/1.1
GET /example.png HTTP/1.1
如果使用HTTP/2的Server Push特征,根據(jù)上面的PUSH模式圖,我們可以看出,Server還沒有收到Client的請求,就把各種資源推送給Client。
拿上面例子繼續(xù)舉例,當Client只請求index.html,但是Server把index.html、style.css、example.png全部發(fā)送給瀏覽器。這樣只需要一輪 HTTP 通信,Client就得到了全部資源。