1. 程式人生 > >HTTP/2幀格式簡介

HTTP/2幀格式簡介

HTTP/2

HTTP/2 ,超文字傳輸協議的第二版。相對於HTTP/1.x 協議的文字傳輸格式,HTTP/2以二進位制的格式進行資料傳輸。因此,具有更小的傳輸體積以及負載,相比於文字解析,二進位制解析更加方便、高校。

HTTP/1.x與HTTP/2

報文(幀)格式

HTTP/1 的請求和響應報文,是由起始行、首部和正文組成,換行符分隔。
HTTP/2 將請求和響應資料分割為更小的幀,並對它們採用二進位制編碼。易於解析。

HTTP1.1報文與HTTP/2幀對比

【 http2.0並沒有改變http1.x的語義,只是把原來http1.x的header和body部分用frame重新封裝了一層而已】

內部對比

位結構

Headers Frame: 幀頭


固定的9個位元組((24+8+8+1+31)/8=9)呈現,變化的為幀的負載(Frame Payload),負載內容是由幀型別(Type)定義。

Length: 幀長度
無符號的自然數,24個位元表示,僅表示幀負載(Frame Payload)所佔用位元組數,不包括幀頭所佔用的9個位元組。 預設大小區間為為0~16,384(2^14),一旦超過預設最大值2^14(16384),傳送方將不再允許傳送,除非接收到接收方定義的SETTINGS_MAX_FRAME_SIZE(一般此值區間為2^14 ~ 2^24)值的通知。
Type幀型別
8個位元表示,定義了幀負載的具體格式和幀的語義,HTTP/2規範定義了10個幀型別,這裡不包括實驗型別幀和擴充套件型別幀
Flags:幀的標誌位


8個位元表示,服務於具體幀型別,預設值為0x0。 8個位元可以容納8個不同的標誌,比如,PADDED值為0x8,二進位制表示為00001000;END_HEADERS值為0x4,二進位制表示為00000100;END_STREAM值為0X1,二進位制為00000001。可以同時在一個位元組中傳達三種標誌位,二進位制表示為00001101,即0x13。因此,後面的幀結構中,標誌位一般會使用8個位元表示,若某位不確定,使用問號?替代,表示此處可能會被設定標誌位
R:幀保留位元位
HTTP/2語境下為保留的位元位,固定值為0X0。
Stream Identifier:流識別符號
無符號的31位元表示無符號自然數。0x0值表示為幀僅作用於連線,不隸屬於單獨的流。

關於幀長度,需要稍加關注: - 0 ~ 2^14(16384)為預設約定長度,所有端點都需要遵守 - 2^14 (16,384) ~ 2^24-1(16,777,215)此區間數值,需要接收方設定SETTINGS_MAX_FRAME_SIZE引數單獨賦值 - 一端接收到的幀長度超過設定上限或幀太小,需要傳送FRAME_SIZE_ERR錯誤 - 當幀長錯誤會影響到整個連線狀態時,須以連線錯誤對待之;比如HEADERS,PUSH_PROMISE,CONTINUATION,SETTINGS,以及幀識別符號不該為0的幀等,都需要如此處理 - 任一端都沒有義務必須使用完一個幀的所有可用空間 - 大幀可能會導致延遲,針對時間敏感的幀,比如RST_STREAM, WINDOW_UPDATE, PRIORITY,需要快速傳送出去,以免延遲導致效能等問題

HTTP2 的幀型別

包含下面幾種型別,對應上圖的Type區域定義。

Frame Type Code
DATA 0x0
HEADERS 0x1
PRIORITY 0x2
RST_STREAM 0x3
SETTINGS 0x4
PUSH_PROMISE 0x5
PING 0x6
GOAWAY 0x7
WINDOW_UPDATE 0x8
CONTINUATION 0x9

幀的標誌位(Flags)

含義如下圖:
幀的標誌位

案例:
假設我們要傳送 0x12345678,流編號為 10 ,型別為DATA,那麼這個Frame的16進製表達就是:
‘000004’ + ‘00’ + ‘00’ + ‘0000000A’ + ‘12345678’

Header幀

HTTP2的 HEADER幀的格式如下:
HEADER幀格式
對應的欄位列表說明如下:
* Pad Length*:受制於PADDED標誌控制是否顯示,8個位元表示填充的位元組數。 可選。Flags:PADDED 設定後要求有此欄位
E:一個位元表示流依賴是否專用,可選項,只在流優先順序PRIORITY被設定時有效 可選。Flags:PRIORITY 設定後要有此欄位
Stream Dependency:31個位元表示流依賴,只在流優先順序PRIORITY被設定時有效 可選。Flags:PRIORITY 設定後要有此欄位
Weight:8個位元(一個位元組)表示無符號的自然數流優先順序,值範圍自然是(1~256),或稱之為權重。只在流優先順序PRIORITY被設定時有效 這個欄位是可選的,並且只在優先順序標記設定的情況下才呈現。
Header Block Fragment:報頭塊分片
Padding:填充的位元組,受制於PADDED標誌控制是否顯示,長度由Pad Length欄位決定
* 注意 * , 只有 Header Block Fragment 是必須的, 其他都看 幀的標誌位Flags 是否設定要有。

所需標誌位:
END_STREAM (0x1): 報頭塊為最後一個,意味著流的結束。
END_HEADERS (0x4): 此報頭幀不需分片,完整的一個幀。後續不再需要CONTINUATION幀幫忙湊齊。若沒有此標誌的HEADER幀,後續幀必須是以CONTINUATION幀傳遞在當前的流中,否則接收者需要響應PROTOCOL_ERROR型別的連線錯誤。
PADDED (0x8): 需要填充的標誌
PRIORITY (0x20): 優先順序標誌位,控制獨立標誌位E,流依賴,和流權重。

  • 其負載為報頭塊分片,若內容過大,需要藉助於CONTINUATION幀繼續傳輸。若流識別符號為0x0,結束段需要返回PROTOCOL_ERROR連線異常。HEADERS幀包含優先順序資訊是為了避免潛在的不同流之間優先順序順序的干擾。
  • 其實一般來講,報文頭部不大的情況下,一個HEADERS就可以完成了,特殊情況就是Cookie欄位超過16KiB大小,不常見。

CONTINUATION 幀

HTTP/2的 CONTINUATION 幀的格式如下:
 CONTINUATION 幀

欄位列表:
Header Block Fragment,用於協助HEADERS/PUSH_PROMISE等單幀無法包含完整的報頭剩餘部分資料。

注意事項:

1 一個HEADERS/PUSH_PROMISE幀後面會跟隨零個或多個CONTINUATION,只要上一個幀沒有設定END_HEADERS標誌位,就不算一個幀完整資料的結束。
2 接收端處理此種情況,從開始的HEADERS/PUSH_PROMISE幀到最後一個包含有END_HEADERS標誌位幀結束,合併的資料才算是一份完整資料拷貝
3 在HEADERS/PUSH_PROMISE(沒有END_HEADERS標誌位)和CONTINUATION幀中間,是不能夠摻雜其它幀的,否則需要報PROTOCOL_ERROR錯誤
標誌位: * END_HEADERS(0X4):表示報頭塊的最後一個幀,否則後面還會跟隨CONTINUATION幀。

HTTP/2的 Data幀

一個或多個DATA幀作為請求、響應內容載體,較為完整的結構如下:
Data幀

欄位:
*Pad Length: 一個位元組表示填充的位元組長度。取決於PADDED標誌是否被設定.
Data: 這裡是應用資料,真正大小需要減去其他欄位(比如填充長度和填充內容)長度。
* Padding*: 填充內容為若干個0x0位元組,受PADDED標誌控制是否顯示。接收端處理時可忽略驗證填充內容。若驗證,可以對非0x0內容填充迴應PROTOCOL_ERROR型別連線異常。
標誌位:
END_STREAM (0x1): 標誌此幀為對應標誌流最後一個幀,流進入了半關閉/關閉狀態。
PADDED (0x8): 負載需要填充,Padding Length + Data + Padding組成。
注意事項:

若流識別符號為0x0,接收者需要響應PROTOCOL_ERROR連線錯誤
DATA幀只能在流處於”open” or “half closed (remote)”狀態時被髮送出去,否則接收端必須響應一個STREAM_CLOSED的連線錯誤。若填充長度不小於負載長度,接收端必須響應一個PROTOCOL_ERROR連線錯誤。