HTTP/2 是一個(gè)應(yīng)用層傳輸協(xié)議,是 HTTP 協(xié)議的第二個(gè)主要版本。HTTP2 主要是基于 google 的 SPDY 協(xié)議,SPDY 的關(guān)鍵技術(shù)被 HTTP2 采納了,因此 SPDY 的成員全程參與了 HTTP2 協(xié)議制定過程
HTTP/2 由互聯(lián)網(wǎng)工程任務(wù)組(IETF)的Hypertext Transfer Protocol Bis (httpbis)工作小組進(jìn)行開發(fā)的,是自1999年HTTP/1.1發(fā)布后的首個(gè)更新
HTTP/2 的主要目標(biāo)包括異步連接多路復(fù)用、頭部壓縮、請求/響應(yīng)管線化等,這些功能可以提高傳輸效率、減少延遲、增加服務(wù)器的處理能力,以及提供更好的安全性
HTTP/2 基于 TLS/1.2 或以上版本的加密連接,簡稱為h2(加密連接)或h2c(非加密連接)。在開放互聯(lián)網(wǎng)上,HTTP/2將只用于https網(wǎng)址,而http網(wǎng)址將繼續(xù)使用HTTP/1.1。這種設(shè)計(jì)旨在增加使用加密技術(shù),以提供強(qiáng)有力的保護(hù)去遏制主動(dòng)攻擊
HTTP/1.1 問題
HTTP/1.1 存在一些問題,其中最主要的問題是隊(duì)頭阻塞(Head-of-Line Blocking)和性能瓶頸
- 隊(duì)頭阻塞:在HTTP/1.1中,每個(gè)請求都需要在一個(gè)TCP連接上按照順序進(jìn)行傳輸。如果一個(gè)請求因?yàn)槟承┰虮蛔枞蜓舆t,后面的請求也必須等待,導(dǎo)致隊(duì)頭阻塞。這會(huì)降低并發(fā)性能和響應(yīng)速度
- 頭部冗余:在HTTP/1.1中,每個(gè)請求和響應(yīng)都包含大量的頭部字段,這些字段在每個(gè)請求和響應(yīng)中都需要重復(fù)傳輸。這導(dǎo)致了頭部冗余和增加了網(wǎng)絡(luò)傳輸?shù)拇笮?/li>
- 單一連接限制:在HTTP/1.1中,每個(gè)請求都需要?jiǎng)?chuàng)建一個(gè)新的TCP連接,而創(chuàng)建和維護(hù)TCP連接會(huì)產(chǎn)生額外的開銷。同時(shí),每個(gè)連接都需要經(jīng)過慢啟動(dòng)和擁塞控制等機(jī)制,導(dǎo)致性能瓶頸
- 無法主動(dòng)推送資源:在HTTP/1.1中,服務(wù)器只能響應(yīng)客戶端的請求,無法主動(dòng)推送資源給客戶端。這導(dǎo)致了客戶端需要發(fā)起多個(gè)請求才能獲取所有需要的資源,增加了網(wǎng)絡(luò)延遲和額外的請求次數(shù)
HTTP/2
HTTP/2 重要概念
- 幀(Frame):HTTP2 中最小通信數(shù)據(jù)單元,每個(gè)幀至少包含了一個(gè)標(biāo)識(stream identifier,簡稱stream id)該幀所屬的流。
- 消息(Message):消息由一個(gè)或多個(gè)幀組成。例如請求的消息和響應(yīng)的消息。
- 流(Stream):存在于 HTTP2 連接中的一個(gè)“虛擬連接通道“,它是一個(gè)邏輯概念。流可以承載雙向字節(jié)流,及是客戶端和服務(wù)端可以進(jìn)行雙向通信的字節(jié)序列。每個(gè)流都有一個(gè)唯一的整數(shù) ID(stream identifier) 標(biāo)識,由發(fā)起流的一端分配給流
單個(gè) HTTP2 連接可以包含多個(gè)同時(shí)打開的流,任何一個(gè)端點(diǎn)(客戶端和服務(wù)端)都可以將多個(gè)流的消息進(jìn)行傳輸。一個(gè) TCP 連接(HTTP2 連接建立在 TCP 連接之上)里可以發(fā)送若干個(gè)流,每個(gè)流中可以傳輸若干條消息,每條消息由若干二進(jìn)制幀組成
任何一端都可以關(guān)閉流。在流上發(fā)送消息的順序很重要,最后接收端會(huì)把 Stream Identifier (同一個(gè)流) 相同的幀重新組裝成完整的消息報(bào)文。特別是 HEADERS 幀和 DATA 幀的順序在語義上非常重要
二進(jìn)制幀層
上圖可以看出,HTTP1.1 是明文文本,而 HTTP2.0 首部(HEADERS)和數(shù)據(jù)消息主體(DATA)都是幀(frame)。frame 是 HTTP2 協(xié)議中最小數(shù)據(jù)傳輸單元
幀 Frame 的格式
一旦建立 HTTP/2 連接,客戶端和服務(wù)器就通過交換幀進(jìn)行通信,幀是協(xié)議中最小的通信單元。所有幀有固定的 9 字節(jié)標(biāo)頭(圖 12-7),其中包含幀的長度、類型、標(biāo)志位字段和 31 位流標(biāo)識符
字段 | 長度 | 語義 |
---|---|---|
Length | 24 bit | 表示 Frame Payload 的長度占用字節(jié)數(shù),幀頭的 9 字節(jié)不包含在 Length 值中 |
Type | 8 bit | 幀類型,決定了幀的格式和語義。實(shí)現(xiàn)時(shí)必須忽略或拋棄未知類型的幀 |
Flags | 8 bit | 用于特定的幀F(xiàn)rame類型語義 |
R(Reserved) | 1 bit | 保留字段 |
Stream Identifier | 31 bit | 流標(biāo)識符,標(biāo)識唯一的 HTTP/2 流 |
Frame Payload | 內(nèi)容主體,由幀的類型決定 |
從技術(shù)上講,該length字段允許每幀最多 2 24 2^{24} 224字節(jié) (~16MB) 的有效負(fù)載。然而,HTTP/2 標(biāo)準(zhǔn)將DATA幀的默認(rèn)最大有效負(fù)載大小設(shè)置為 每幀字節(jié) 2 14 2^{14} 214 (~16KB),并允許客戶端和服務(wù)器協(xié)商更高的值
幀類型
幀類型,在 HTTP2 中共分為 10 種類型:
每一種類型幀都由一個(gè) 8 位類型代碼來識別。每種幀類型在建立和管理整個(gè)連接或單個(gè)數(shù)據(jù)流時(shí)都有不同的作用
Type | Code(Type 值) | 說明 |
---|---|---|
DATA | 0x00 | 數(shù)據(jù)幀(type=0x00),內(nèi)容主題信息Frame Payload。比如一個(gè)或多個(gè) DATA 幀可用于傳輸請求或響應(yīng)的信息內(nèi)容 |
HEADERS | 0x01 | 頭幀(type=0x01),用于打開一個(gè)流,另外還攜帶一個(gè)首部的塊片段 |
PRIORITY | 0x02 | 優(yōu)先級幀(type=0x02),在 rfc9113 中這個(gè)字段已棄用。PRIORITY 幀可以在任何流狀態(tài)下發(fā)送,包括空閑或關(guān)閉的流 |
RST_STREAM | 0x03 | 流終止幀(type=0x03),允許立即終止一個(gè)流。發(fā)送 RST_STREAM 表示請求取消流或表明發(fā)生錯(cuò)誤的情況 |
SETTINGS | 0x04 | 設(shè)置幀(type=0x04),設(shè)置兩端連接方式的配置參數(shù) |
PUSH_PROMISE | 0x05 | 推送幀(type=0x05),服務(wù)端的推送,告訴對端打算推送數(shù)據(jù)給你了 |
PING | 0x06 | PING幀(type=0x06),確定一個(gè)空閑連接是否仍然可用,也可以測量端點(diǎn)間往返時(shí)間(RTT)。PING 幀可以從任意端點(diǎn)發(fā)出 |
GOAWAY | 0x07 | GOAWAY幀(type=0x07),用于發(fā)起關(guān)閉連接的請求,或發(fā)出嚴(yán)重錯(cuò)誤的信號。GOAWAY 允許端點(diǎn)優(yōu)雅的停止接收新流,同時(shí)仍然完成對先前建立的流的處理 |
WINDOW_UPDATE | 0x08 | WINDOW_UPDATE幀(type=0x08),用于實(shí)現(xiàn)流控??梢宰饔迷趩为?dú)的某個(gè)流上(指定具體的 Stream Identifier ),也可以作用在整個(gè)連接上(Stream Identifier 為 |
CONTINUATION | 0x08 | 延續(xù)幀 (type=0x9),用于繼續(xù)傳送首部塊片段字節(jié)序列 |
HTTP2 中幀 type 和 flags 可能的組合(圖表中 x 符號表示該類型的幀的 flags 可以取的值)
HTTP/2 特性
多路復(fù)用
HTTP/2 引入了多路復(fù)用機(jī)制,允許在同一個(gè)TCP連接上同時(shí)發(fā)送多個(gè)請求和響應(yīng),而不需要按照順序逐個(gè)發(fā)送。這樣可以避免HTTP 1.0中的隊(duì)頭阻塞問題,提高了并發(fā)性能和響應(yīng)速度。
從圖中可以看到在 HTTP1.1 中,請求 index.html 資源,響應(yīng)完畢后就關(guān)閉連接了。而在 HTTP2 中,請求完資源后,連接仍然是打開的,后面還可以繼續(xù)使用這個(gè)連接通道傳輸數(shù)據(jù)。
上圖可以看到在一個(gè) HTTP2 connection 中,客戶端和服務(wù)端雙方都能夠向?qū)Ψ桨l(fā)送多個(gè)流數(shù)據(jù)(stream 1、stream 3、stram 5),在 HTTP2 中用這個(gè) stream ID 來標(biāo)識幀和流的對應(yīng)關(guān)系
更多關(guān)于 stream流 和 multiplexing多路復(fù)用的內(nèi)容,請查看鏈接:https://httpwg.org/specs/rfc9113.html#rfc.section.5
頭部壓縮
HTTP/2 使用了專門的 HPACK 壓縮算法對請求和響應(yīng)的頭部進(jìn)行壓縮,減少了傳輸?shù)念^部大小。這可以降低網(wǎng)絡(luò)帶寬的消耗,特別對于包含大量重復(fù)頭部字段的請求非常有效
HPACK 原理:
- 客戶端和服務(wù)端共同維護(hù)了一份靜態(tài)字典表(Static Table),其中包含了常見頭部名及常見頭部名稱與值的組合的代碼
- 客戶端和服務(wù)端根據(jù)先入先出的原則,共同維護(hù)了一份能動(dòng)態(tài)添加內(nèi)容的動(dòng)態(tài)字典表(Dynamic Table)
- 客戶端和服務(wù)端支持基于靜態(tài)哈夫曼碼表的哈夫曼編碼(Huffman Coding)
二進(jìn)制傳輸
HTTP/2 使用二進(jìn)制格式對數(shù)據(jù)進(jìn)行傳輸和解析,而不再使用HTTP 1.0的文本格式。這樣可以提高解析效率,減少了傳輸數(shù)據(jù)的大小,并且更容易實(shí)現(xiàn)新的特性和擴(kuò)展
服務(wù)端推送
服務(wù)端推送是一種在客戶端請求之前發(fā)送數(shù)據(jù)的機(jī)制。在 HTTP2 中,服務(wù)器可以對客戶端的一個(gè)請求發(fā)送多個(gè)響應(yīng)。除了對原始請求響應(yīng)外,還可以向客戶端推送額外的數(shù)據(jù)。
服務(wù)端推送的目的是讓服務(wù)器通過預(yù)測它收到請求后有哪些相關(guān)資源需要返回,從而減少資源請求往返次數(shù)。
比如在 HTML 頁面的請求后,通常是對該頁面應(yīng)用的樣式表和腳本的請求,當(dāng)這些資源被服務(wù)端直接推送給客戶端時(shí),客戶端就不需要單獨(dú)給服務(wù)器發(fā)送請求來獲取這些資源了
所有服務(wù)端推送數(shù)據(jù)流都由 PUSH_PROMISE 幀發(fā)起。如上圖所示,在 page.html 文件中包含資源文件 script.js 和 style.css??蛻舳讼蚍?wù)端請求 page.html 文件,服務(wù)端發(fā)現(xiàn) page.html 文件中包含了這兩種資源文件,就會(huì)把這兩種資源文件推送給客戶端,以此來減少客戶端的請求次數(shù)
在實(shí)踐中,服務(wù)端推送很難有效使用。因?yàn)樾枰?wù)端正確預(yù)測客戶端發(fā)出的額外請求,預(yù)測必須同時(shí)考慮緩存、內(nèi)容協(xié)商和用戶行為等因素。預(yù)測錯(cuò)誤又可能導(dǎo)致性能下降,因?yàn)榉?wù)端發(fā)送了額外的數(shù)據(jù)。特別是推送了大量數(shù)據(jù)時(shí)可能與重要的響應(yīng)數(shù)據(jù)發(fā)生線路爭用等問題
流量控制
在 HTTP2 中,使用流來實(shí)現(xiàn)多路復(fù)用,這種會(huì)對 TCP 連接使用產(chǎn)生競爭,從而導(dǎo)致流傳輸被阻塞。流量控制是確保在同一連接上的流不會(huì)相互干擾。流量控制既能用于單個(gè)流也能用于整個(gè)連接。
HTTP2 使用 WINDOW_UPDATE 幀提供流量控制功能
-
基于流的流量控制:
- HTTP/2中的流量控制是基于每個(gè)數(shù)據(jù)流(Stream)的,而不是基于整個(gè)連接
- 每個(gè)數(shù)據(jù)流都有自己的流量控制窗口(Flow Control Window),用于控制發(fā)送方發(fā)送的數(shù)據(jù)量
- 發(fā)送方必須遵守接收方指定的流量控制窗口大小,確保不會(huì)發(fā)送超過窗口大小的數(shù)據(jù)
-
流量控制窗口的調(diào)整:
- 每個(gè)數(shù)據(jù)流都有一個(gè)初始的流量控制窗口大小,用于指示發(fā)送方可以發(fā)送的初始數(shù)據(jù)量
- 接收方可以通過發(fā)送WINDOW_UPDATE幀來調(diào)整流量控制窗口的大小,以告知發(fā)送方可以發(fā)送更多的數(shù)據(jù)
- 發(fā)送方在發(fā)送數(shù)據(jù)之前需要檢查流量控制窗口的大小,確保發(fā)送的數(shù)據(jù)不會(huì)超過窗口大小
-
連接級流量控制:
- HTTP/2還引入了連接級流量控制,用于控制整個(gè)連接上的數(shù)據(jù)傳輸
- 連接級流量控制窗口是所有數(shù)據(jù)流窗口大小的總和,用于控制整個(gè)連接上的數(shù)據(jù)傳輸量
- 發(fā)送方必須同時(shí)考慮連接級流量控制窗口和每個(gè)數(shù)據(jù)流的流量控制窗口,確保不會(huì)發(fā)送超過任何一個(gè)窗口大小的數(shù)據(jù)
-
窗口更新和處理順序:
- 接收方可以通過發(fā)送WINDOW_UPDATE幀來增加流量控制窗口的大小
- 發(fā)送方在接收到WINDOW_UPDATE幀后,會(huì)更新相應(yīng)的窗口大小,并根據(jù)新的窗口大小繼續(xù)發(fā)送數(shù)據(jù)
- 接收方處理WINDOW_UPDATE幀的順序非常重要,以確保正確更新窗口大小
通過這些流量控制原則,HTTP/2可以有效地控制數(shù)據(jù)的傳輸量,防止一方過載導(dǎo)致的性能問題。流量控制機(jī)制可以調(diào)整數(shù)據(jù)流的速率,保證發(fā)送方和接收方之間的平衡,優(yōu)化整個(gè)連接的傳輸效率
流優(yōu)先級
在 HTTP2 中,一個(gè)消息可以拆分為多個(gè)單獨(dú)的幀,并且允許來自多個(gè)流的幀被多路復(fù)用,客戶端和服務(wù)端幀傳輸可能是亂序傳輸,所以優(yōu)先級順序就變成了一個(gè)關(guān)鍵性能考慮因素
HTTP2 允許每個(gè)流具有關(guān)聯(lián)的權(quán)重和依賴性:
- 每個(gè)流可以分配一個(gè) 1-256 范圍之間整數(shù)權(quán)重
- 每個(gè)流都可以被賦予對另外一個(gè)流的依賴性
更多流優(yōu)先級信息,比如流的依賴關(guān)系、依賴權(quán)重、優(yōu)先級(依賴)重排、優(yōu)先級狀態(tài)管理等內(nèi)容,詳見rfc.section.5.3文章來源:http://www.zghlxwxcb.cn/news/detail-838737.html
參考資料:文章來源地址http://www.zghlxwxcb.cn/news/detail-838737.html
- HTTP/2
- HTTP2 協(xié)議長文詳解
- HTTP/2 FrameTypes
- NGINX HTTP/2 白皮書
到了這里,關(guān)于超越HTTP/1.1:探索HTTP/2的無盡可能性的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!