有些地方後續補充完整
HTTP/1 的問題
1. 隊頭阻塞
HTTP/1 有個特性叫管道化(pipelining),允許一次傳送一組請求,但是隻能按照傳送順序依次接受。
因此,如果某個請求應答出現狀況,那麼剩下的工作都會被阻塞在那次請求應答之後,即隊頭阻塞。它會阻礙網路傳輸和 Web 頁面渲染。
目前措施:現代瀏覽器會針對單個域名開啟 6 個連線,通過各個連線分別傳送請求。(某種程度上的並行)
2. 低效的 TCP 利用
HTTP/1 並不支援多路複用,所以瀏覽器一般會針對指定域名開啟 6 個併發連線,這意味著擁塞視窗波動也會並行發生 6 次。TCP 協議保證那些連線都能正常工作,但是不能保證它們的效能上最優的。
3. 臃腫的訊息首部
雖然 HTTP/1 提供了壓縮被請求內容的機制,但是訊息首部卻無法壓縮。
4. 受限的優先順序設定
5. 第三方資源
HTTP/2
大致分為兩部分:
- 分幀層,即 h2 多路複用能力的核心部分;
- 資料或 http 層
特性
-
二進位制協議
h2 的分幀層是基於幀的二進位制協議。
-
首部壓縮
-
多路複用
-
加密傳輸
幀
HTTP/2 是基於幀的協議,採用分幀是為了將重要資訊都封裝起來,讓協議的解析方可以輕鬆閱讀、解析並還原資訊。
HTTP/1 不是基於幀的,而是以文字分隔的。問題:
- 速度慢且容易出錯
- 一次只能處理一個請求或響應,完成之前不能停止解析
- 無法預判解析需要多少記憶體
有了幀,處理協議的程式能預先知道會收到什麼。(因為幀會有固定的位元組去表達資訊)
前 9 個位元組對於每個幀是一致的。(通過讀取這些位元組,可以準確知道在整個幀中期望的位元組數)
幀的英文是 frame,在我的理解有一種結構體的意思,相對於基於文字的要有結構有規律一些
名稱(幀欄位) | 長度 | 描述 |
---|---|---|
Length | 3 位元組 | 表示幀負載的長度 |
Type | 1 位元組 | 當前幀型別 |
Flags | 1 位元組 | 具體幀型別的標識 |
R | 1 bit | 保留位,不要設定 |
Stream Identifier | 31 bit | 每個流的唯一 ID |
Frame Payload | 長度可變 | 真實的幀內容,長度在 Length 欄位設定 |
名稱(幀型別) | 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 資料塊 |
優勢
h1 由於是依靠分隔符的,因此只能處理完一個請求或響應,才能處理下一個;h2 是分幀的,所以請求和響應可以交錯甚至多路複用。
(個人理解就是,h1 中多個請求或者響應連線在一起,由於只是靠分隔符解析,因此無法判斷是多個內容連線起來的;而 h2 中多個幀連線在一起,由於幀更像個結構體,並且有長度資訊,解析程式能夠知道解析到哪裡算一個幀的結束。)
流
定義:HTTP/2 連線上獨立的、雙向的幀序列交換。
如果客戶端想要發出請求,它會開啟一個新的流,然後伺服器將在這個流上回復。
**因為有分幀,所以多個請求和響應可以交錯,而不會互相阻塞。**流 ID 用來標識幀所屬的流。
服務端推送
推送使伺服器能夠主動將物件發給客戶端。
首部壓縮
HPACK 是種表查詢壓縮方案,利用霍夫曼編碼獲得接近 GZIP 的壓縮率。
參考
- 《HTTP/2 基礎教程》