协议选型:HTTP/1.1 vs HTTP/2 vs HTTP/3
聊到 HTTP 协议选型,很多同学第一反应是“哪个新选哪个”。但我在项目里踩过坑——盲目升级 HTTP/2 结果反向代理没配好,性能反而下降。所以咱们得把每个版本的核心差异、适用场景和坑位都捋清楚。
版本演进的核心驱动力
说白了,HTTP 每次升级都是为了解决前一个版本的性能瓶颈。HTTP/1.1 解决了连接复用和缓存的问题,HTTP/2 解决了队头阻塞和头部冗余,HTTP/3 则用 QUIC(基于 UDP)彻底干掉 TCP 层面的队头阻塞。
HTTP/1.1:老而弥坚的基础款
HTTP/1.1 引入持久连接(Keep-Alive)和管道化(Pipeline),但管道化在现实中基本没被浏览器支持——因为实现太难,容易死锁。我曾经在一个 CDN 项目里试过开启管道化,结果中间代理直接把乱序响应丢掉了,浪费半天时间排查。
- 持久连接:默认启用,减少 TCP 握手次数。
- Host 头:支持虚拟主机,一台服务器托管多个域名。
- 块传输编码:流式响应,不需要 Content-Length。
- 缓存控制:Cache-Control、ETag 等更加灵活。
实际上 HTTP/1.1 最大的痛点是队头阻塞——同一个连接上的请求必须排队,前一个响应没回来,后面的请求就得等着。浏览器为了缓解这个问题,通常对同一域名开 6~8 个 TCP 连接,但连接数又受浏览器限制,而且每个连接都要三次握手和慢启动。
HTTP/2:多路复用的救星
HTTP/2 引入二进制分帧、多路复用、头部压缩(HPACK)和服务器推送。其中最核心的就是多路复用——一个 TCP 连接上可以同时交错传输多个请求和响应,彻底解决队头阻塞问题。
但 HTTP/2 也有自己的队头阻塞——发生在 TCP 层。当 TCP 丢包时,整个连接上的所有流都会被阻塞,直到丢包重传完成。这就是为什么 HTTP/2 在弱网环境可能比 HTTP/1.1 还差:因为 HTTP/1.1 有多个连接,丢一个包只影响那个连接,而 HTTP/2 只有一个连接,丢包影响全局。
HTTP/3:QUIC 带来的革命
HTTP/3 改用基于 UDP 的 QUIC 协议。QUIC 有几个关键改进:
- 0-RTT 握手:在已经连接过的场景下,可以直接发送数据,减少延迟。
- 独立流:每个流独立处理丢包,一个流丢包不影响其他流。
- 连接迁移:IP 地址变化(比如手机从 WiFi 切到 4G)不会中断连接。
- 内置加密:默认 TLS 1.3,不再有明文 HTTP。
我在做一个跨国直播项目时,用 QUIC 把首帧延迟从 800ms 降到了 300ms 以下,效果非常明显。但要注意——QUIC 依赖于 UDP,很多企业防火墙和 NAT 设备对 UDP 有限制或丢包,部署时需要仔细测试。
选型对比表
| 维度 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 传输层 | TCP | TCP | QUIC(UDP) |
| 连接复用 | 每域多连接 | 多路复用(单连接) | 多路复用(单连接) |
| 队头阻塞 | 连接级别 | TCP 级别 | 流级别(无) |
| 握手延迟 | 2~3 RTT(含 TLS) | 2~3 RTT(含 TLS) | 0~1 RTT |
| 头部压缩 | 无 | HPACK | QPACK |
| 服务器推送 | 否 | 是(但很少用) | 是 |
| 适用场景 | 简单 API、少量静态资源 | 复杂页面、大量并行请求 | 弱网、低延迟、移动端 |
协议栈概览图
下面这张图展示了三种 HTTP 版本的协议栈结构,以及它们共用的上层语义。注意 HTTP/1.1 和 HTTP/2 都跑在 TCP 上,而 HTTP/3 的传输层换成了 QUIC。
选型决策流程
实际操作中,我一般按下面的步骤做决定:
- 确认基础设施支持:你的反向代理(Nginx、Envoy、HAProxy)是否支持 HTTP/2 或 HTTP/3?CDN 厂商是否支持?如果不支持,降级到 HTTP/1.1。
- 评估网络质量:如果用户群体主要在弱网环境下(比如移动端、跨国链路),优先考虑 HTTP/3。如果你主要服务内网或低延迟接入,HTTP/2 已经足够。
- 计算请求数量:页面首屏请求超过 30 个且都是小文件?HTTP/2 多路复用优势巨大。如果只有不到 10 个请求,HTTP/1.1 也不差。
- 考虑兼容性:老客户端(比如 Android 4.x、iOS 9 以下)不支持 HTTP/2,更不用说 HTTP/3。建议保留 HTTP/1.1 作为底线。
listen 443 ssl http2;
listen 443 quic reuseport;
http2 on;
add_header Alt-Svc 'h3=":443"; ma=86400';
兼容性注意事项
嗯,这里要注意几个硬性约束:
- HTTP/2 必须在 TLS 上才能被浏览器使用,而且 TLS 1.2 及以上。
- HTTP/3 目前仍处于快速迭代期,QUIC 版本号还在更新(目前是 v1),如果中间设备(如防火墙)对 UDP 做 DPI,可能导致连接失败。
- CDN 回源:如果你用 CDN,回源链路通常还是 HTTP/1.1 或 HTTP/2。用户端到 CDN 边缘节点可以使用 HTTP/3,但边缘节点到源站往往走 HTTP/2。我曾经遇到过 CDN 开启 h3 后,源站没有对应配置,导致回源失败,页面白屏。
最后补充一句:别急着全上 HTTP/3。先跑灰度,用 A/B 测试对比核心指标,比如首屏时间、连接成功率、用户感知延迟。数据说话最稳。