答案:HTTP2核心特性
HTTP/2 的多路复用解决了 HTTP 层的队头阻塞,为什么 TCP 层还会阻塞?如果 TCP 连接上某个 Stream 的数据包丢失,为什么其他 Stream 也要等待?
答案:
HTTP/2 的多路复用确实解决了应用层的队头阻塞——在 HTTP/1.1 中,浏览器对同一域名只能开 6~8 个 TCP 连接,如果第 1 个请求的 JS 文件很大,后面的 CSS 请求只能排队等待。HTTP/2 把所有请求放在一条 TCP 连接上,用 Stream ID 区分,理论上可以并行传输。
但 TCP 是可靠、按序传输的协议。假设飞翔官网的 HTTP/2 连接上同时传输 3 个 Stream:
- Stream 1:首页 HTML(优先级高)
- Stream 3:logo.png
- Stream 5:app.js
如果 Stream 3 的某个 TCP 数据包(比如序列号 1000~1499)在传输中丢失了,TCP 的滑动窗口机制会要求发送方重传这个包。在丢失的包被成功重传并确认之前,TCP 不会把后续任何数据(包括 Stream 1 和 Stream 5 的数据)交付给应用层,即使这些数据已经完好到达接收端缓冲区。
这就是TCP 层的队头阻塞——TCP 不知道上层 HTTP/2 的 Stream 概念,它只看到一个连续的字节流,必须保证字节流的完整和有序。
发送端:
Stream1: [A1][A2][A3]...
Stream3: [B1][B2][B3][B4]...
Stream5: [C1][C2][C3]...
TCP 层(混成一个字节流):
[A1][B1][A2][B2][C1][B3]...[B4丢失]...[A3][C2]...
接收端:
B4 丢失 → TCP 暂停交付 → A3、C2 已在缓冲区但无法交给 HTTP/2
→ 所有 Stream 都卡住,等待 B4 重传
这也是 HTTP/3 改用 QUIC(基于 UDP)的核心动机——QUIC 在传输层就实现了 Stream 隔离,一个 Stream 的丢包不会影响其他 Stream。
空少想给飞翔官网启用 HTTP/2,但担心老客户端不支持。HTTP/2 的协商机制是什么?不支持 HTTP/2 的客户端会怎样降级?
答案:
HTTP/2 的协商机制是完全向后兼容的,老客户端会自动降级到 HTTP/1.1,无需空少担心。
HTTPS 场景(主流方式)—— ALPN(Application-Layer Protocol Negotiation):
ALPN 是 TLS 握手扩展,客户端在 ClientHello 中发送自己支持的协议列表(如 h2, http/1.1),服务器从中选择最优的回复。这是目前主流浏览器启用 HTTP/2 的标准方式。
# 用 OpenSSL 查看飞翔官网的 ALPN 协商
echo | openssl s_client -alpn h2,http/1.1 -connect www.feixiang.net:443 | grep ALPN
# 输出示例:
# ALPN protocol: h2
HTTP 场景(较少见)—— Upgrade 机制:
客户端先发送 HTTP/1.1 请求,携带 Upgrade: h2c 头,服务器如果支持则返回 101 Switching Protocols,双方切换到 HTTP/2。但主流浏览器不支持 h2c(HTTP/2 over cleartext),只支持 h2(HTTP/2 over TLS)。
不支持 HTTP/2 的客户端会怎样?
- 老浏览器(IE11 及更早):TLS 握手时不发送 ALPN 扩展,服务器默认选择 HTTP/1.1
- curl 老版本:默认 HTTP/1.1,需显式加
--http2才尝试 - 某些 API 客户端:如果代码写死了
HTTP/1.1,完全不受影响
# 强制使用 HTTP/1.1 访问(模拟老客户端)
curl --http1.1 -I https://www.feixiang.net
# HTTP/1.1 200 OK
# 显式请求 HTTP/2
curl --http2 -I https://www.feixiang.net
# HTTP/2 200 OK
空少(运维工程师)在飞翔公司的部署策略是:Nginx 同时监听 HTTP/1.1 和 HTTP/2,listen 443 ssl http2; 这一行就同时支持两种协议,ALPN 自动协商,老客户端零感知降级。
HTTP/2 要求强制 HTTPS 吗?实际上主流浏览器(Chrome、Firefox、Safari)对 HTTP/2 的实现有什么限制?这对飞翔官网的部署策略有什么影响?
答案:
HTTP/2 协议本身不要求 HTTPS。 RFC 7540 明确规定了两种实现:
h2:HTTP/2 over TLS(基于 ALPN 协商)h2c:HTTP/2 over cleartext(基于 HTTP/1.1 Upgrade 机制)
但主流浏览器实际上强制要求 HTTPS:
| 浏览器 | HTTP/2 支持条件 |
|---|---|
| Chrome | 仅支持 h2(TLS + ALPN),拒绝 h2c |
| Firefox | 仅支持 h2,拒绝 h2c |
| Safari | 仅支持 h2,拒绝 h2c |
| Edge | 仅支持 h2,拒绝 h2c |
这意味着:虽然理论上你可以用 curl --http2-prior-knowledge http://example.com 直接访问 h2c,但真实用户使用的浏览器全部要求 HTTPS。从实际部署角度,HTTP/2 ≈ HTTPS。
对飞翔官网部署策略的影响:
必须先完成全站 HTTPS 改造:如果还有 HTTP 页面,启用 HTTP/2 对这些用户没有意义(他们会回退到 HTTP/1.1)
TLS 版本要求:HTTP/2 的 ALPN 需要 TLS 1.2+,旧版 OpenSSL(< 1.0.1)不支持,服务器需要升级
证书配置优化:HTTP/2 多路复用减少了连接数,但 TLS 握手成本还在。翼王要求飞翔官网启用 OCSP Stapling 和 Session Ticket 复用,减少 TLS 握手开销:
# 飞翔官网 Nginx HTTP/2 配置(空少维护)
server {
listen 443 ssl http2;
server_name www.feixiang.net;
ssl_certificate /etc/nginx/ssl/feixiang.crt;
ssl_certificate_key /etc/nginx/ssl/feixiang.key;
# TLS 优化
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE+AESGCM:ECDHE+CHACHA20;
ssl_prefer_server_ciphers on;
# OCSP Stapling(减少证书验证延迟)
ssl_stapling on;
ssl_stapling_verify on;
# Session 复用
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets on;
# HTTP/2 特定优化
http2_push_preload on; # 服务端推送(谨慎使用)
}
- 监控与灰度:空少先用 CDN 的灰度功能,对 10% 流量启用 HTTP/2,监控错误率和延迟变化,确认无误后再全量开启。
靓晴(前端负责人)还建议:启用 HTTP/2 后,不要再做域名分片(sharding)。HTTP/1.1 时代把静态资源拆到 cdn1.feixiang.net、cdn2.feixiang.net 是为了突破 6 连接限制,HTTP/2 下单连接多路复用更高效,域名分片反而增加不必要的 TLS 握手开销。