协议选型: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/2 适合多请求、高并发的现代页面;HTTP/3 适合弱网环境和对延迟极度敏感的业务(比如实时通信、在线游戏)。

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 连接上可以同时交错传输多个请求和响应,彻底解决队头阻塞问题。

我个人的习惯:如果网站主要使用 HTTPS,且资源请求量较大(比如超过 50 个静态资源),我会优先选择 HTTP/2。不过要注意,HTTP/2 只对 HTTPS 生效(实际上所有主流浏览器都要求 HTTP/2 运行在 TLS 上)。

但 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/3 目前还不是 RFC 标准(2022 年正式发布 RFC 9114),但主流浏览器已经支持。如果你要对外提供服务,建议通过协商方式降级——比如用 Alt-Svc 头部告诉客户端“我可以提供 h3,但你优先使用 h2 或 h1.1”。我曾经见过只配了 h3 的服务,客户端升级后连不上,白白损失了一部分流量。

选型对比表

维度 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。

HTTP 协议栈演进对比 HTTP/1.1 TLS(可选) TCP IP HTTP/2 HPACK + 二进制分帧 TLS(必须) TCP IP HTTP/3 QPACK QUIC (TLS 1.3) UDP IP HTTP/1.1 HTTP/2 HTTP/3 共享 HTTP 语义(方法、状态码、头字段) 关键差异 • HTTP/1.1 和 HTTP/2 基于 TCP,存在 TCP 层队头阻塞; • HTTP/3 基于 QUIC(UDP),无队头阻塞,0-RTT 握手; • HTTP/2 必须使用 TLS,HTTP/1.1 可选,HTTP/3 内置 TLS 1.3。

选型决策流程

实际操作中,我一般按下面的步骤做决定:

  1. 确认基础设施支持:你的反向代理(Nginx、Envoy、HAProxy)是否支持 HTTP/2 或 HTTP/3?CDN 厂商是否支持?如果不支持,降级到 HTTP/1.1。
  2. 评估网络质量:如果用户群体主要在弱网环境下(比如移动端、跨国链路),优先考虑 HTTP/3。如果你主要服务内网或低延迟接入,HTTP/2 已经足够。
  3. 计算请求数量:页面首屏请求超过 30 个且都是小文件?HTTP/2 多路复用优势巨大。如果只有不到 10 个请求,HTTP/1.1 也不差。
  4. 考虑兼容性:老客户端(比如 Android 4.x、iOS 9 以下)不支持 HTTP/2,更不用说 HTTP/3。建议保留 HTTP/1.1 作为底线。
我的常见部署方案:同时开启 HTTP/1.1、HTTP/2 和 HTTP/3,通过 ALPN 和 Alt-Svc 协商。这样无论客户端能力如何,都能自动选择最优协议。Nginx 配置大致是:
listen 443 ssl http2;
listen 443 quic reuseport;
http2 on;
add_header Alt-Svc 'h3=":443"; ma=86400';
一个小坑:开启 HTTP/2 后,别忘了把“域名分片”和“CSS Sprites”等针对 HTTP/1.1 的优化去掉。反过来说,如果你决定降级回 HTTP/1.1,那就要重新用上这些技巧。我之前接手过一个项目,HTTP/2 下还保留了十几个子域名分片,结果每个子域名都要做 TLS 握手,白白浪费资源。

兼容性注意事项

嗯,这里要注意几个硬性约束:

  • 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 测试对比核心指标,比如首屏时间、连接成功率、用户感知延迟。数据说话最稳。