1.写在前面
前面的博客已经介绍完了HTTP2相关协议的一些内容了,现在需要介绍剩下的东西。
2.服务器端的主动消息推送
服务器推送的价值
- 提前将资源推送至浏览器缓存
- 特性
- 推送可以基于已经发送的请求,例如客户端请求 html,主动推送 js 文件
- 实现方式
- 推送资源必须对应一个请求
- 请求由服务器端PUSH_PROMISE 帧发送
- 响应在偶数 ID 的 STREAM 中发送
当获取 HTML 后,需要 CSS 资源时
浏览器触发方式:需要两次往返!
PUSH_PROMISE 方式
-
在 Stream1 中通知客户端 CSS 资源即将来临
-
在 Stream2 中发送 CSS 资源(Stream1 和 2 可以并发!)
服务器推送 PUSH
PUSH 帧的格式
-
PUSH_PROMISE 帧,type=0x5,只能由服务器发送
PUSH 推送模式的禁用
- SETTINGS_ENABLE_PUSH(0x2)
- 1表示启用推送功能
- 0表示禁用推送功能
3.stream 的状态变迁
Stream 特性
- 一条 TCP 连接上,可以并发存在多个处于 OPEN 状态的 Stream
- 客户端或者服务器都可以创建新的 Stream
- 客户端或者服务器都可以首先关闭 Stream
- 同一条 Stream 内的 Frame 帧是有序的
- 从 Stream ID 的值可以轻易分辨 PUSH 消息
- 所有为发送 HEADER/DATA 消息而创建的流,从1、3、5 等递增奇数开始
- 所有为发送 PUSH 消息而创建的流,从 2、4、6 等递增偶数开始
Message 特性
- 一条 HTTP Message 由 1 个 HEADER(可能含有 0 个或者多个持续帧构成)及 0 个或者多个 DATA 帧构成
- HEADER 消息同时包含 HTTP/1.1 中的 start line 与 headers 部分
- 取消 HTTP/1.1 中的不定长 Chunk 消息
GET 消息发送示例
POST 消息发送示例
Stream 流的状态
-
帧符号
- H: HEADERS 帧
- PP: PUSH_PROMISE 帧
- ES: END_STREAM 标志位
- R: RST_STREAM 帧
-
流状态
- idle: 起始状态
- closed:关闭状态
- open: 可以发送任何帧
- half closed 单向关闭
- remote: 不再接收数据帧
- local: 不能再发送数据帧
- reserved
- remote
- local
4.RST_STREAM 帧及常见错误码
RST_STREAM 帧(type=0x3)
-
HTTP2 多个流共享同一连接,RST 帧允许立刻终止一个未完成的流
-
RST_STRAM 帧不使用任何 flag
-
RST_STREAM 帧的格式
常见错误码
- NO_ERROR (0x0): 没有错误。GOAWAY帧优雅关闭连接时可以使用此错误码
- PROTOCOL_ERROR (0x1): 检测到不识别的协议字段
- INTERNAL_ERROR (0x2):内部错误
- FLOW_CONTROL_ERROR (0x3): 检测到对端没有遵守流控策略
- SETTINGS_TIMEOUT (0x4): 某些设置帧发出后需要接收端应答,在期待时间内没有得到应答则由此错误码表示
- STREAM_CLOSED (0x5): 当Stream已经处于半关闭状态不再接收Frame帧时,又接收到了新的Frame帧
- FRAME_SIZE_ERROR (0x6): 接收到的Frame Size不合法
- REFUSED_STREAM (0x7): 拒绝先前的Stream流的执行
- CANCEL (0x8): 表示Stream不再存在
- COMPRESSION_ERROR (0x9): 对HPACK压缩算法执行失败
- CONNECT_ERROR (0xa): 连接失败
- ENHANCE_YOUR_CALM (0xb): 检测到对端的行为可能导致负载的持续增加,提醒对方“冷静”一点
- INADEQUATE_SECURITY (0xc): 安全等级不够
- HTTP_1_1_REQUIRED (0xd): 对端只能接受HTTP/1.1协议
5.不同请求的优先级
Priority 优先级设置帧
- 帧类型:type=0x2
- 不使用 flag 标志位字段
- Stream Dependency:依赖流
- Weight权重:取值范围为 1 到 256。默认权重16
- 仅针对 Stream 流,若 ID 为 0 试图影响连接,则接收端必须报错
- 在 idle 和 closed 状态下,仍然可以发送 Priority 帧
HEADER 帧的格式
数据流优先级
exclusive 标志位
5.不同于 TCP 的流量控制
为什么需要 HTTP/2 应用层流控?
-
HTTP/1.1 中由 TCP 层进行流量控制
-
前提:HTTP/1 的 TCP 连接上没有多路复用
-
-
HTTP/2 中,多路复用意味着多个 Stream 必须共享 TCP 层的流量控制
-
问题:多 Stream 争夺 TCP 的流控制,互相干扰可能造成 Stream 阻塞
-
代理服务器内存有限,上下游网速不一致时,通过流控管理内存
-
由应用层决定发送速度
- HTTP/2 中的流控制既针对单个 Stream,也针对整个 TCP 连接
- 客户端与服务器都具备流量控制能力
- 单向流控制:发送和接收独立设定流量控制
- 以信用为基础:接收端设定上限,发送端应当遵循接收端发出的指令
- 流量控制窗口(流或者连接)的初始值是 65535 字节
- 只有 DATA 帧服从流量控制
- 流量控制不能被禁用
WINDOW_UPDATE 帧
-
type=0x8,不使用任何 flag
-
窗口范围 1 to 231-1 (2,147,483,647)字节
- 0 是错误的,接收端应返回 PROTOCOL_ERROR
-
当 Stream ID 为 0 时表示对连接流控,否则为对 Stream 流控
-
流控仅针对直接建立 TCP 连接的两端
-
代理服务器并不需要透传 WINDOW_UPDATE 帧
-
接收端的缩小流控窗口会最终传递到源发送端
-
流控制窗口
-
窗口大小由接收端告知
-
窗口随着 DATA 帧的发送而减少
SETTINGS_MAX_CONCURRENT_STREAMS 并发流
- 并发仅统计 open 或者 half-close 状态的流(不包含用于推送的 reserved 状态)
- 超出限制后的错误码
- PROTOCOL_ERROR
- REFUSED_STREAM
6.HTTP/2 与 gRPC 框架
gRPC:支持多语言编程、基于 HTTP/2 通讯的中间件
gRPC 测试
- 官网:https://grpc.io/
- 基于 Python 语言搭建测试环境
- https://grpc.io/docs/quickstart/python/
- 测试程序
- git clone -b v1.21.0 https://github.com/grpc/grpc
- cd grpc/examples/python/helloworld
- 服务器:python greeter_server.py
- 客户端:python greeter_client.py
- 注意
- 欲抓取环回报文,请安装时勾选【install Npcap in Winpcap API-Compatible Mode 】
- 如果 Npcap Loopback Adapter 未抓取到环回报文,请尝试其他接口
- 若 50051 端口未被识别为 http/2,请手动设置"解码为 HTTP/2”
helloworld.proto
Protocol Buffers 编码:消息结构
Protocol Buffers 编码:数据类型 Wire Type
Protocol Buffers 字符串编码举例
7.HTTP/2 的问题及 HTTP/3 的意义
TCP 以及 TCP+TLS 建链握手过多的问题
多路复用与 TCP 的队头阻塞问题
TCP的问题
- 由操作系统内核实现,更新缓慢
QUIC 协议在哪一层?
使 Chrome 支持 QUIC
IETF QUIC 协议草案
QUIC 协议组的 Milestones
8.HTTP/3:QUIC 协议概述
HTTP/3 与 QUIC 协议
HTTP3 的连接迁移
-
允许客户端更换 IP 地址、端口后,仍然可以复用前连接
解决了队头阻塞问题的 HTTP3
-
UDP 报文:先天没有队列概念
HTTP3:1RTT 完全握手
会话恢复场景下的 0RTT 握手
HTTP3:0RTT 恢复会话握手
9.七层负载均衡做了些什么?
四层负载均衡
七层负载均衡协议转换举例
HTTP 协议转换
- request line 起始行
- URL 重写(包括 query 参数转换)
- method 变换
- http version 版本变换
- header 头部
- header 名字、值作转换(如 HTTP/2 索引表中查询头部,转换为适配协议格式)
- 负载均衡对 header 作修改
- 隐藏某个 header(例如隐藏 X-Accel-Expires 等头部)
- 新增 header(例如 CORS 允许跨域访问)
- 修改 header 的 value 值(例如修改 Server 头部的值)
- body 包体
- 对内容使用通用算法(如压缩算法)转换
- 按固定协议格式对内容进行转换
WAF 防火墙(Web Application Firewall)
- request line 请求行
- 检查 URL 及 query 参数是否合法(如 SQL 注入)
- method 方法是否合法(例如阻止 TRACE 方法)
- http version 版本是否合法(例如不接收 HTTP/1.0 请求)
- header 头部
- 检查 header 项是否符合应用场景要求
- body 包体
- 对于FORM表单等通用格式做过滤
负载均衡算法
缓存功能
10.写在最后
至此所有的HTTP2的协议的内容就介绍完了