特点:流式传输。二进制分帧。TLS优先。多路复用。服务器预推送。HPACK头部压缩。
3.1、握手与时序
http1.1 升级协议 http/2
GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
如果服务端支持,则升级请求
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
如果服务器不支持,则正常返回
HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html
https:
HTTPS 直接先由TLS握手升级,并使用连接序言初始化(connection preface),序言固定数据:
0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
解码为:
PRI * HTTP/2.0\r\n
\r\n
SM\r\n
\r\n
升级成功后,服务器端必须立马返回一个可为空的SETTINGS帧
流的生命周期
idle:空闲状态。
reserved(local):流在本地已保留。
reserved(remote):流在对端已保留。
open:流已初始化。
half-closed(local):本端已准备好接收数据(本端只能发送WINDOW_UPDATE
,PRIORITY
和 RST_STREAM
帧)。
half-closed (remote):对端已准备好接收数据(对端只能发送WINDOW_UPDATE
,PRIORITY
和 RST_STREAM
帧),对应的本端可以发送数据。
closed:流关闭。
3.2、基本格式
+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) |
+=+=============================================================+
| Frame Payload (0...) ...
+---------------------------------------------------------------+
Length(24位):Frame Payload的数据长度,初始最大长度为2^14(16384,0x4000)完全最大长度为2^24-1(16,777,215, 0xFFFFFF)。
Type(8位):帧类型,当前有10种
Flags(8位):帧标志位
R:空位,强制为 0x0
Stream Identifier(31位):帧流ID:客户端发起的用奇数/服务端发起的用偶数,0x0链接控制,0x1升级1.1到2的流响应,数字递增。
Frame Payload:帧荷载数据
Type 帧类型
Frame Type | 名称 | Code | 可发送的生命周期 |
---|---|---|---|
DATA | 数据荷载帧 | 0x0 | open、half-closed (remote) |
HEADERS | 头数据帧 | 0x1 | idle、reserved (local)、open、half-closed (remote) |
PRIORITY | 设置当前流的权重命令帧 | 0x2 | idle、closed |
RST_STREAM | 立即终止流命令帧 | 0x3 | 除idle皆可 |
SETTINGS | 流配置帧 | 0x4 | |
PUSH_PROMISE | 预启动新流 | 0x5 | open、half-closed (remote) |
PING | 确认网络连通性,返回flag:0x1确认 | 0x6 | 任何 |
GOAWAY | 已处于连接关闭流程或发出严重错误状态 | 0x7 | |
WINDOW_UPDATE | 协商控制DATA帧最大长度 | 0x8 | |
CONTINUATION | 附加发送头信息的帧 | 0x9 | 必须跟在 HEADERS、PUSH_PROMISE 帧之后 |
帧类型对应有效的Flags
3.3、帧格式详解
SETTINGS 帧
用于同步客户端和服务器之间的参数设置
+-------------------------------+
| Identifier (16) |
+-------------------------------+-------------------------------+
| Value (32) |
+---------------------------------------------------------------+
| Identifier (16) |
+-------------------------------+-------------------------------+
| Value (32) |
+---------------------------------------------------------------+
字段解释:
Identifier:字段key
Value:字段值
flag:
0x0(默认)用于发送设置,该流必须带有设置的荷载。
0x1(ACK)时用于确认接收到对端的设置并已应用,该流中不允许有荷载。
HEADER (Type=0x1) 帧
+---------------+ |Pad Length? (8)| +-+-------------+-----------------------------------------------+ |E| Stream Dependency? (31) | +-+-------------+-----------------------------------------------+ | Weight? (8) | +-+-------------+-----------------------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+
字段解释:
E:指示流的依赖性,如果为 0x1,则后31位是 Stream Dependency。如果流Flag存在PRIORITY位 则会存在。
Weight:权重,当前流的的权重,和E、Stream Dependency 公用。
Header Block Fragment:头部数据,数据格式在RFC7541定义。
flag:
0x1(END_STREAM):流结束标志
0x4(END_HEADERS):表示头信息最后一帧标志,不会继续发送子头部(CONTINUATION)帧。
0x8(PADDED):表示荷载中存在填充格式。
0x20(PRIORITY):标识该帧依赖于其他流,应该降低优先级到荷载中对应的设置中。
DATA (Type=0x0) 帧荷载
+---------------+ |Pad Length? (8)| +---------------+-----------------------------------------------+ | Data (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+
字段解释:
Pad Length:帧填充Padding域的长度
Data:应用数据荷载
Padding:一段0x0 填充的数据。(rfc7540 10.7解释为了提高安全性)
flag:
0x1(END_STREAM):流结束标志。
0x8(PADDED):表示荷载中存在填充格式。
PUSH_PROMISE(Type=0x5)预启动一个新的流
+--------------------+ |Pad Length? (8)| +-+-------------+-----------------------------------------------+ |R| Promised Stream ID (31) | +-+-----------------------------+-------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+ | Padding (*) ... +---------------------------------------------------------------+
字段解释:
Pad Length(填充长度):8位字段,以八位位组为单位,包含帧填充的长度。 该字段仅在PADDED标志置位时才存在。
R:一个保留位。
Promised Stream ID:一个无符号的31位整数,用于标识由PUSH_PROMISE保留的流。 承诺流标识符必须是发送方发送的下一个流的有效选择。
Header Block Fragment(header块片段):包含请求头部字段的header块片段。
Padding:填充字节。
flag:
0x4(END_HEADERS):表示头信息最后一帧标志,不会继续发送子头部(CONTINUATION)帧。
0x8(PADDED):荷载包含填充。
CONTINUATION帧
+---------------------------------------------------------------+ | Header Block Fragment (*) ... +---------------------------------------------------------------+
用于补充 HEADERS帧 和 PUSH_PROMISE帧 的额外头数据