文章目录
- 二进制帧
- HTTP/2 中的帧、消息和流
- 1. 帧(Frame)
- 2. 消息(Message)
- 3. 流(Stream)
- @总结
- 示例:
- 二进制帧结构
- 1.帧头部结构
- 2.帧负载数据
- 请求和响应多路复用
链接参考:https://web.dev/articles/performance-http2?hl=zh-cn#binary_framing_layer
二进制帧
在HTTP2.0中引入了新的编码机制,所有传输的数据都会被分割,并采用二进制格式编码
HTTP/2 所有性能增强的核心是新的二进制分帧层
,它规定了 HTTP 消息的封装方式,并在客户端和服务器之间传输。
为了保证HTTP不受影响,那就需要在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层。在二进制分帧层上,HTTP2.0会将所有传输的信息分为更小的消息和帧,并采用二进制格式编码,其中HTTP1.x的首部信息会被封装到Headers帧,而Request Body则封装到Data帧。
在 HTTP/2 中,所有通信都在一个 TCP 连接
上进行,并被分割成更小的二进制帧
。这些帧按序列号发送和接收
,并在接收端重新组装成完整的消息
。这一层的实现为 HTTP/2 带来了显著的性能改进。
所以http2和http1.1互相不理解(但是应用无需感知这些变化,客户端和服务器会帮我们执行所有底层的动作)
HTTP/2 中的帧、消息和流
1. 帧(Frame)
定义和作用
:
- 定义:帧是 HTTP/2 协议中的
最小单位
。所有的 HTTP/2 通信都通过帧进行。每个
帧都包含
一个固定长度的头部(标识所属于的stream流)
和一个可变长度的负载 - 作用:
帧
是 HTTP/2 协议实现多路复用
的基础,通过帧的分割和重组,能够在单个连接上并行传输多个请求和响应
特点
:
- 头部:固定为 9 字节,包含长度、类型、标志和流标识符等信息。
- 负载:可变长度,具体内容根据帧的类型不同而有所变化。
常见类型
:
- DATA 帧:传输消息主体。
- HEADERS 帧:传输头部信息。
- PRIORITY 帧:设置流的优先级。
- RST_STREAM 帧:重置流。
- SETTINGS 帧:协商连接参数。
- PUSH_PROMISE 帧:服务器推送资源。
- PING 帧:检查连接的连通性。
- GOAWAY 帧:通知对端即将关闭连接。
- WINDOW_UPDATE 帧:进行流量控制。
2. 消息(Message)
定义和作用
:
- 定义:消息是由一组帧组成的完整的逻辑请求或响应。在 HTTP/2 中,消息通常包含一个 HEADERS 帧后跟一个或多个 DATA 帧(
一个完整的帧序列,用来映射到逻辑的请求或者响应信息
) - 作用: HTTP 协议的基本单元,用于传递客户端和服务器之间的请求和响应。通过将消息分割成多个帧,HTTP/2 能够更有效地传输和管理数据
特点
:
- 组成:
HEADERS 帧 + (可选的)多个 DATA 帧
。 - 逻辑完整性:
消息
表示一个完整的 HTTP 请求或响应
,包含所有必要的头部和主体信息。
3. 流(Stream)
定义和作用
:
- 定义:流是 HTTP/2 中的一个
独立的、双向的字节流
,包含多个帧
。每个流都有一个唯一的标识符
,用于区分同一连接上的不同流(在一个建立连接内的双向字节流,能承载一个或者多个消息
)(TCP连接中的一个虚拟通道,可以承载双向的消息
) - 作用:流是 HTTP/2 实现
多路复用的关键
,通过在一个连接上同时存在多个流,可以并行处理多个请求和响应,避免了HTTP/1.1 的队头阻塞
问题。
特点
:
- 双向性:流可以在客户端和服务器之间双向传输数据(
真正意义的全双工
) - 唯一标识符:每个流都有一个唯一的 31 位标识符,客户端和服务器使用
奇偶数区分流的来源(客户端创建的流为奇数,服务器创建的流为偶数)
。 - 优先级:流可以设置优先级,以优化资源分配和响应时间。
@总结
所有通信都在一个TCP连接上进行,该连接可以承载任意数量的双向流(streams)(一个流,一次请求与响应)
每个流都有一个唯一的标识符和可选的优先级信息,用于承载双向消息
每条消息是一个逻辑上的HTTP消息,例如请求或响应,由一个或多个帧组成
帧是通信的最小单位,承载特定类型的数据,例如HTTP头部、消息负载等。来自不同流的帧可以交替发送,并通过每个帧头部中的嵌入流ID标识符重新组装
示例:
- 客户端发送请求:客户端发送一个包含 HEADERS 帧和多个 DATA 帧的消息。消息被分割成多个帧,并通过流 1 传输。
- 服务器响应请求:服务器通过流 1 发送一个包含 HEADERS 帧和多个 DATA 帧的消息作为响应。
- 并行请求:客户端可以通过流 3 和流 5 同时发送其他请求,服务器可以通过相应的流进行响应。
二进制帧结构
帧的组成部分
- 帧头部(9 字节)
- 帧负载数据(可变长度)
+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+---------------+---------------+---------------+
|R| Stream Identifier (31) |
+=+=============================================+
| Frame Payload |
+-----------------------------------------------+
1.帧头部结构
帧头部固定为 9 字节,由以下字段组成:
- 长度(Length)(3 字节), 表示帧负载数据的长度,确保接收方能正确读取和处理帧数据。它的值范围是 0 到 16,383(2^14 - 1)
- 类型(Type)(1 字节)表示帧的类型,接收方能够按照特定帧类型的规则处理该帧
常见帧类型:
- 0x0:DATA 帧
- 0x1:HEADERS 帧
- 0x2:PRIORITY 帧
- 0x3:RST_STREAM 帧
- 0x4:SETTINGS 帧
- 0x5:PUSH_PROMISE 帧
- 0x6:PING 帧
- 0x7:GOAWAY 帧
- 0x8:WINDOW_UPDATE 帧
- 标志(Flags)(1 字节),表示该帧的一些特殊属性,提供附加信息,如是否是最后一个帧(END_STREAM),是否包含头部(END_HEADERS),是否包含优先级信息(PRIORITY)
- 常见标志位:
- 0x1:END_STREAM,表示这是流的最后一个帧。
- 0x4:END_HEADERS,表示 HEADERS 帧的结束。
- 0x20:PRIORITY,表示包含优先级信息。
- 流标识符(Stream Identifier)(4 字节)
帧所属的流的唯一标识符
,该帧所属的流,以便接收方将帧数据归属到正确的流中。流标识符是一个 31 位的无符号整数,最高位保留,必须设置为 0。
2.帧负载数据
帧负载数据的长度和内容根据帧类型的不同而变化。以下是一些常见帧类型的负载数据示例:
-
DATA 帧:
- 负载数据:实际传输的数据(如 HTML 内容、二进制数据)。
- 特殊字段:可能包含 PADDED 数据(填充字节)。
-
HEADERS 帧:
- 负载数据:包含头部字段的压缩表示(使用 HPACK 算法)。
- 特殊字段:可能包含 PRIORITY 信息和 PADDED 数据。
-
PRIORITY 帧:
- 负载数据:包含优先级信息,如依赖的流标识符和权重。
-
SETTINGS 帧:
- 负载数据:包含连接的配置信息,如最大帧大小、最大并发流数等。
-
PING 帧:
- 负载数据:包含一个 8 字节的不可变数据,用于检测连接的连通性。
请求和响应多路复用
使用 HTTP/1.x 时,如果客户端想要发出多个并行请求以提高性能,则必须使用多个 TCP 连接。这是 HTTP/1.x 传送模型的直接结果,该行为可确保每个连接一次只传送一个响应(响应排队)。更糟糕的是,这也会导致队首阻塞(http1.x队头阻塞)
,以及底层 TCP 连接的效率低下。
HTTP/2 中新的二进制分帧层消除了这些限制并实现了完整的请求和响应多路复用,方法是允许客户端和服务器将 HTTP 消息分解为独立的帧,交错发送,然后在另一端重新组装这些帧
。
该快照捕捉了同一连接内传输的多个数据流。客户端正在向服务器传输 DATA 帧(流 5),而服务器正在将交错的帧序列发送到客户端,以便流 1 和流 3。因此,正在传输三个并行流
。
能够将 HTTP 消息分解为独立的帧,交错这些帧
,然后在另一端重新组装这些帧
,是 HTTP/2 最重要的增强功能。事实上,它在所有 Web 技术的整个堆栈中带来了众多性能优势的连锁效应,使我们能够:
- 并行交错地发送多个请求,请求之间互不影响。
- 并行交错地发送多个响应,响应之间互不影响。
- 使用一个连接并行发送多个请求和响应。
- 消除不必要的延迟并提高可用网络容量的利用率,从而缩短网页加载时间。
- 在HTTP1.x中,我们是通过文本的方式传输数据。基于文本的方式传输数据存在很多缺陷,文本的表现形式有多样性,因此要做到
健壮性
考虑的场景必然有很多,但是二进制则不同,只有0和1的组合,因此选择了二进制传输,实现方便且健壮。