分帧:把报文大卸八块
HTTP/2 最根本的变化:不再整发整收,把每个请求/响应切成一个个二进制帧(HEADERS 帧、DATA 帧等),帧上带着 stream 编号,多个 stream 的帧在同一条 TCP 连接上交错传输:
HTTP/1.1(串行):
──请求A────响应A────────请求B────响应B──→ 时间
(B 在干等 A)
HTTP/2(交错):
请求A的帧 ▙▚▙▚▚▙ stream 1
请求B的帧 ▚▚▚▚▚▚▚▚ stream 3 ← A 慢不影响 B 全速走
请求C的帧 ▙▙▙ stream 5
接收端按 stream 编号把帧各自拼回去效果立竿见影:一条连接从“单车道”变“多车道立交”,同域名 6 连接上限、域名分片全部作废——官方口径是连接越少越好。
stream:逻辑上的独立通道
每对请求响应独占一个 stream(客户端发的用奇数号,服务端推送用偶数号),stream 之间没有次序绑定。帧还带优先级和依赖树(PRIORITY),浏览器会提示“CSS 比 JS 急”。不过实践中优先级机制各家实现五花八门,效果参差,HTTP/3 里干脆重做了。帧大小有上限(默认 16KB),大响应会被切成上百个 DATA 帧,这正是交错得以发生的前提——粒度越小,插队越灵活。
HPACK:把重复的头部压掉
1.1 时代每个请求都背一遍完整的头,页面加载几百个请求,User-Agent、Cookie、Accept 反复传输。HPACK 两招解决:一是静态表——61 个常见头字段(如 :method: GET)双方约定好,直接发个索引号;二是动态表——连接级缓存,见过的自定义头(如长 Cookie)存起来,后续只传索引。实测重复头能压掉 80%~95%。注意动态表是连接级的,压得越狠越不能频繁断连——又一个复用长连接的理由。
它治不了的和它没成的
两件事要泼冷水:第一,TCP 层队头阻塞原封不动——所有 stream 挤一条 TCP 连接,丢一个包大家一起等(上一篇对比过),弱网下甚至不如 1.1 的多连接;第二,Server Push 基本失败——服务端猜资源需求主动推,实际命中差、浪费流量,浏览器干脆移除了支持。HTTP/2 的核心遗产是分帧复用思想,这个思想在 QUIC 里被搬到了传输层,才真正治了队头(第十九篇)。
部署:一行配置的事
# Nginx 开启 HTTP/2(要求 TLS)
server {
listen 443 ssl http2;
...
}
# 验证
$ curl -sI https://note.example.com | grep -i http
HTTP/2 200 ← 已经在用 2 了
$ curl -s --http2 -o /dev/null -w "%{http_version}
" https://note.example.com
2浏览器与 Nginx 之间走 HTTP/2,但 Nginx 到后端应用之间通常还是 1.1——应用收到的仍是老协议,业务无感知,升级成本几乎为零。下一篇讲 HTTPS 的另一半:TLS 握手到底慢在哪一步,TLS 1.3 怎么把 RTT 砍到 1。
评论 (0)