HTTP2核心特性
概念引入
想象飞翔科技的官网 www.feixiang.net 是一家繁忙的餐厅。HTTP/1.1 时代,每桌客人(每个请求)都要独占一条送餐通道(TCP 连接)。如果 A 桌点了份慢炖牛排(大文件),B 桌的凉菜(小请求)只能干等——这就是队头阻塞(Head-of-Line Blocking)。
更糟的是,每次上菜服务员都要重复念一遍"飞翔科技、广州、粤菜"(重复头部),浪费大量口舌。
HTTP/2(RFC 7540,2015年发布)给餐厅来了次智能化改造:所有订单合并到一条高速传送带,小菜大餐交错送达,常用信息用暗号代替,厨房还能主动推配菜。
飞翔场景:空少(前端)发现官网首页要加载 80+ 个资源,HTTP/1.1 下浏览器只能开 6-8 个 TCP 连接,大量请求排队。启用 HTTP/2 后,首屏时间从 3.2 秒降到 1.1 秒。
核心内容
HTTP/1.1 的性能瓶颈
HTTP/2 四大核心特性
1. 二进制分帧(Binary Framing)
HTTP/1.1 是文本协议,人类可读但机器解析慢。HTTP/2 把消息分割成更小的帧(Frame),每帧带类型和所属流(Stream)ID。
帧类型包括:HEADERS(头部)、DATA(数据)、SETTINGS(配置)、PRIORITY(优先级)、RST_STREAM(取消流)等。
2. 多路复用(Multiplexing)
所有请求/响应共享一条 TCP 连接,通过 Stream ID 区分。就像一条高速公路上有多条虚拟车道:
Stream ID 为奇数是客户端发起的,偶数是服务器发起的(服务器推送)。
3. 头部压缩(HPACK)
HPACK 是 HTTP/2 的头部压缩算法,结合三种技术:
- 静态表:预定义 61 个常用头部字段(如
:method: GET、:status: 200) - 动态表:连接级缓存,把出现过的头部存入索引,后续用索引号代替
- 哈夫曼编码:对字符串值进行熵编码,进一步压缩
飞翔场景:空少统计发现,HTTP/1.1 下请求头平均 800 字节,HPACK 压缩后降到 100 字节以内,省了近 90%。
4. 服务器推送(Server Push)
服务器能主动发送资源,不用等客户端请求。就像服务员看到点了牛排,主动推上黑胡椒酱和刀叉。
# 客户端请求 HTML
GET /index.html
# 服务器响应 HTML,同时推送 CSS 和 JS
PUSH_PROMISE (stream=2) :path=/style.css
PUSH_PROMISE (stream=4) :path=/app.js
HEADERS (stream=1) 200 OK + DATA index.html
HEADERS (stream=2) 200 OK + DATA style.css
HEADERS (stream=4) 200 OK + DATA app.js
注意:推送必须搭配
PUSH_PROMISE帧提前告知客户端,避免推送缓存里已有的资源。HTTP/3 中服务器推送已被弃用,因为实践中容易推错/推重。
流、帧、消息的层次关系
- 连接(Connection):1 条 TCP 连接
- 流(Stream):连接内的虚拟通道,有优先级和依赖关系
- 消息(Message):完整的请求或响应,由 HEADERS + 零或多个 DATA 帧组成
- 帧(Frame):最小传输单位,带 9 字节头部(长度、类型、标志、Stream ID)
流优先级与依赖
客户端可以告诉服务器"哪个流更重要":
通过 PRIORITY 帧设置权重(1~256)和依赖关系,服务器据此分配带宽。
HTTP/2 的队头阻塞问题
HTTP/2 解决了 HTTP 层的队头阻塞,但TCP 层的队头阻塞仍在:
如果某个 Stream 的数据包在 TCP 层丢失,TCP 要求重传并按序交付,导致该连接上所有 Stream 都卡住。这是 HTTP/3 改用 QUIC(基于 UDP)的核心动机。
HTTP/1.1 vs HTTP/2 对比
| 特性 | HTTP/1.1 | HTTP/2 |
|---|---|---|
| 连接数 | 6-8 条 TCP | 1 条 TCP |
| 传输格式 | 文本 | 二进制帧 |
| 队头阻塞 | HTTP 层阻塞 | HTTP 层解决,TCP 层仍在 |
| 头部压缩 | 无(gzip只压body) | HPACK |
| 服务器推送 | 不支持 | 支持(实践中已弃用) |
| 优先级 | 无 | 流权重+依赖 |
本篇小结
- HTTP/2 通过四大特性解决 HTTP/1.1 性能瓶颈:二进制分帧、多路复用、头部压缩(HPACK)、服务器推送
- 二进制分帧将消息拆分为带 Stream ID 的帧,为交错传输奠定基础
- 多路复用让多个请求/响应共享单条 TCP 连接,通过 Stream ID 区分,彻底解决 HTTP 层队头阻塞
- HPACK 结合静态表、动态表、哈夫曼编码,将头部体积压缩 80% 以上
- 服务器推送允许服务器主动发送资源,但 HTTP/3 已弃用,实践中需谨慎使用
- 流优先级让客户端指导服务器分配带宽,重要资源优先传输
- HTTP/2 仍存在 TCP 层队头阻塞,这是 HTTP/3 引入 QUIC 的根本原因
动手实践
温馨提示: 以下实践示例中涉及的域名(如
www.feixiang.net)、公司场景和接口均为虚构数据,仅用于演示协议原理,实际执行时可能不会产生文档中描述的效果。建议将命令中的域名替换为你自己可访问的真实地址进行练习。
实践:检查网站是否启用 HTTP/2
# 用 curl 查看协议版本
curl -I --http2 https://www.feixiang.net 2>&1 | grep -i "HTTP/2"
# 用 nghttp 详细查看帧信息(需安装 nghttp2)
nghttp -v https://www.feixiang.net
# 用 openssl 检查 ALPN 协商(HTTP/2 需要 h2 ALPN)
openssl s_client -alpn h2 -connect www.feixiang.net:443 </dev/null 2>/dev/null | grep ALPN
实践:对比 HTTP/1.1 和 HTTP/2 的加载速度
# 强制 HTTP/1.1 下载
curl --http1.1 -o /dev/null -w "HTTP/1.1: %{time_total}s\n" https://www.feixiang.net
# HTTP/2 下载
curl --http2 -o /dev/null -w "HTTP/2: %{time_total}s\n" https://www.feixiang.net
实践:思考题
- HTTP/2 的多路复用解决了 HTTP 层的队头阻塞,为什么 TCP 层还会阻塞?如果 TCP 连接上某个 Stream 的数据包丢失,为什么其他 Stream 也要等待?
- 空少想给飞翔官网启用 HTTP/2,但担心老客户端不支持。HTTP/2 的协商机制是什么?不支持 HTTP/2 的客户端会怎样降级?
- HTTP/2 要求强制 HTTPS 吗?实际上主流浏览器(Chrome、Firefox、Safari)对 HTTP/2 的实现有什么限制?这对飞翔官网的部署策略有什么影响?