从 HTTP/1.1 的瓶颈说起
很多个人站长在网站变慢的时候,第一反应是升级服务器配置,却忽略了一个成本更低、收益更明显的优化方向——升级 HTTP 协议版本。HTTP 协议从 1997 年的 1.1 版本一路走到今天的 2.0 和 3.0,每一次大版本升级都解决了上一代最痛的问题。这篇文章就用实测数据,带你看清楚 HTTP/2 和 HTTP/3 到底能带来多少提升,以及怎么在 Nginx 上把它们启用起来。
HTTP/1.1 时代最大的痛点是队头阻塞。浏览器和服务器之间一条连接同一时刻只能处理一个请求,页面里几十个资源就只能排队一个个下载,虽然 1.1 支持了 Keep-Alive 长连接,但排队问题没有根本解决。当年的主流优化手段是把图片、脚本拆到多个域名下,用域名分片来绕过连接数限制,这套土办法在 HTTP/2 普及之后基本可以扔掉了。
一、HTTP/2 带来了什么
HTTP/2 在 2015 年正式发布,核心改进有四个。第一是多路复用,一条 TCP 连接上可以同时跑几十个请求和响应,彻底解决了队头阻塞,域名分片这种 hack 从此失去意义;第二是头部压缩,用 HPACK 算法压缩请求头,重复的 Cookie、User-Agent 等字段只传输一次增量,头部体积能减少百分之八九十;第三是二进制分帧,协议从文本格式改为二进制格式,解析效率更高;第四是服务器推送 Server Push,服务器可以主动把 CSS、图片推给浏览器,不过这个特性因为缓存命中率低、容易造成浪费,后来被 Chrome 团队废弃了,现在主流建议是关掉它。
对用户最直观的感受是:页面资源越多,HTTP/2 的加速效果越明显。一个引用了几十个 JS、CSS、图片的页面,在 HTTP/2 下所有资源并发传输,加载时间常常能缩短百分之三十到五十。这也是为什么 2015 年以后全球主流网站几乎都切到了 HTTP/2。
二、HTTP/2 的短板与 HTTP/3 的解法
HTTP/2 虽然解决了应用层的队头阻塞,但底层依赖的 TCP 协议仍然存在队头阻塞:一个数据包丢失,TCP 要等重传,后续所有数据都得排队。网络越差、丢包率越高,这个问题越严重。另外 HTTP/2 建立连接需要 TCP 三次握手加 TLS 握手,移动网络环境下往返延迟很高。
HTTP/3 的方案是彻底换掉传输层:基于谷歌开源的 QUIC 协议,跑在 UDP 之上。QUIC 把 TCP 的可靠传输、TLS 1.3 加密、连接管理全部融合进用户态协议里,带来三个关键优势。一是 0-RTT 连接:老用户重连时第一个请求就能带上数据,省掉一整轮往返;二是无队头阻塞:每个流独立传输,一个流丢包不影响其他流;三是连接迁移:手机从 WiFi 切到 4G/5G,IP 变了连接也不断,视频不卡顿。代价是 UDP 流量在某些网络环境下会被运营商限速或丢包,而且需要服务端和客户端同时支持。
三、Nginx 启用 HTTP/2 实测
启用 HTTP/2 只需要在 Nginx 的监听指令上加一个 http2 参数,前提是网站必须开启 HTTPS,因为 HTTP/2 在浏览器端强制要求加密传输。Nginx 1.25.1 之后的新语法是这样的:
server {
listen 443 ssl;
http2 on;
server_name www.example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
}旧版本则写成 listen 443 ssl http2; 这种形式。改完配置执行 nginx -t 检查语法,然后 nginx -s reload 平滑重载。用 curl 验证是否生效:curl -I --http2 https://www.example.com/,如果响应头里出现 HTTP/2 200 就说明已经启用成功。我在一台 1 核 1G 的测试服务器上对比过,一个包含 42 个资源的博客页面,HTTP/1.1 全量加载约 3.8 秒,切到 HTTP/2 后降到 2.1 秒,提升接近百分之四十五,而且这个提升不花一分钱。
四、Nginx 启用 HTTP/3
HTTP/3 在 Nginx 里需要额外的 QUIC 支持。从 Nginx 1.25.0 开始,官方加入了实验性的 HTTP/3 模块 ngx_http_v3_module,编译时需要 --with-http_v3_module 参数,并且依赖 OpenSSL 3.0 以上版本或者 BoringSSL。启用配置要点是:监听 443 端口时同时启用 quic 和 reuseport,并添加 Alt-Svc 响应头通知浏览器该站点支持 HTTP/3:
server {
listen 443 ssl;
listen 443 quic reuseport;
http2 on;
server_name www.example.com;
add_header Alt-Svc 'h3=":443"; ma=86400';
}个人站长如果不想折腾编译,更省事的方案是套 Cloudflare 这类 CDN:在 Cloudflare 后台把网络协议设置为 HTTP/3 开启,源站只需要支持 HTTP/2,用户访问时 Cloudflare 边缘节点会自动协商 HTTP/3。实测下来,在国内网络环境下 HTTP/3 的提升主要看线路质量:网络抖动大的场景收益明显,走优化线路时和 HTTP/2 差距不大。
五、怎么科学地做对比测试
对比测试建议用 curl 加 -w 参数输出详细的计时数据:curl -w "DNS:%{time_namelookup} 连接:%{time_connect} TLS:%{time_appconnect} 首字节:%{time_starttransfer} 总耗时:%{time_total}" -o /dev/null -s https://www.example.com/。分别用 --http1.1、--http2、--http3 跑三轮取平均值,注意用 -o /dev/null 丢弃响应体,避免把下载时间算进去。多测几次、换不同时段,才能排除网络波动的影响。另外要提醒一句:服务器在国内的话,443 端口 UDP 流量可能被部分运营商限制,HTTP/3 连接建不起来时浏览器会自动回落到 HTTP/2,这属于正常降级,不影响网站访问。
六、常见问题与踩坑提醒
问:为什么我开启了 HTTP/2,页面速度却没有明显变化?答:先检查网站是不是真的走了 HTTP/2:浏览器开发者工具的 Network 面板里,Protocol 列显示 h2 才是生效,显示 http/1.1 说明配置没生效或者还在用旧语法。其次,HTTP/2 的收益和页面资源数量成正比,如果一个页面只有十几个资源、总体积很小,提速感受本来就不明显。另外,如果你之前用域名分片、雪碧图等手段做了大量 1.1 时代的优化,这些手段在 HTTP/2 下反而可能拖慢速度,建议逐步撤掉。
问:HTTP/2 下还需要合并 CSS 和 JS 文件吗?答:不再需要刻意合并,因为多路复用让每个文件都能独立并发传输,强行合并成一个超大文件反而会失去并行度、拉长单文件下载时间。合理的做法是拆分成职责清晰的小文件,配合浏览器缓存,把长期不变的文件设置足够长的 Cache-Control 过期时间。
问:国内服务器启用 HTTP/3 有什么要注意的?答:首先云厂商安全组和系统防火墙都要放行 UDP 443 端口,只放行 TCP 443 的话 QUIC 握手直接失败;其次确认 Nginx 版本至少 1.25 并且编译时带上了 http_v3 模块;最后要做好心理预期,部分运营商对 UDP 流量有限速或者丢包策略,HTTP/3 建连失败时会自动回落到 HTTP/2,这是正常降级不是故障。想快速体验的话,套 Cloudflare 免费版是最省事的路线。
问:老版本 Nginx 怎么升级才能用 HTTP/3?答:Debian/Ubuntu 可以直接用官方源升级到最新稳定版,CentOS 建议切换到 Nginx 官方 yum 源。升级前先备份 nginx.conf 和站点配置文件,升级后用 nginx -t 验证语法,再执行 nginx -s reload 平滑重载。注意新版对 listen 指令的语法有变化,http2 参数从 listen 里挪到了单独的 http2 on; 指令,照着文档改即可。
问:HTTP/2 下 Nginx 的连接数配置要调整吗?答:多路复用意味着一个浏览器连接可以承载大量请求,连接总数反而下降,但每个连接的存活时间变长。可以适当提高 worker_connections,并合理设置 keepalive_requests 与 keepalive_timeout 让连接复用更充分;HTTP/2 的单连接并发流上限默认是 128,个人站点基本用不满,不用特意调整。
总的来说,HTTP/2 是当前性价比最高的免费提速手段,强烈建议所有 HTTPS 站点立刻启用;HTTP/3 是面向未来的升级,适合网络环境复杂、移动端用户多的站点提前布局。协议升级本身不复杂,收益却是实打实的,值得每个站长花半小时搞定它。最后提醒一点:如果网站套了 CDN,协议协商是在 CDN 边缘节点完成的,源站配不配 HTTP/3 要看 CDN 的透传策略,先搞清楚协议在哪一层终止,再动手改源站配置,别改了源站发现没效果还以为是配置写错了。