HTTP/2协议升级:你网站卡顿的真凶,可能就藏在协议层

打开 Chrome 开发者工具,Network 标签页里密密麻麻排着几十个请求——有的在 pending,有的卡在 waiting for TTFB。你刚优化完图片、清掉冗余 JS、甚至换了 CDN,可首屏还是慢半拍。别急着调优代码了,先看看右上角那一列“Protocol”:如果全是 http/1.1,那问题大概率不在你写的逻辑里,而在你还在用的这个协议上。

HTTP/1.1 是个好协议,但它是为 2005 年的网页设计的。今天的页面动辄上百个资源、嵌套加载、动态渲染,它早就扛不住了。而你的竞品,很可能已经切到 HTTP/2 —— 不声不响,但用户滑动更顺、点击响应更快。

多路复用到底能省多少时间?

HTTP/1.1 规定:同一个域名下,浏览器最多只开 6 个 TCP 连接。
30 个资源?前 6 个先走,剩下 24 个排队。
每个连接都要三次握手、慢启动、TLS 协商……光是建立连接,就能耗掉几百毫秒。

HTTP/2 把这层枷锁拆了。所有请求共享一个 TCP 连接,请求和响应可以交错传输。服务器不用等上一个响应发完,就能开始处理下一个请求。
我接手过一个电商详情页,JS/CSS/图片加起来 120+ 个资源。切到 HTTP/2 后,TTFB 没变,但页面渲染完成时间缩短了不少,尤其滚动时不再出现“突然白一下”的卡顿——因为关键样式和脚本不用排队等前面的图片下载完才能加载。

至于“用多个子域名绕过 6 连接限制”?老办法确实存在过。但现在它反而成了拖累:每个子域名都要单独做 DNS 查询、TLS 握手,还浪费了 HTTP/2 的多路复用优势。直接收编到一个域名下,更干净,也更快。

头部压缩怎么帮你省带宽?

HTTP/1.1 的请求头是明文发的。每次请求都带上完整的 CookieUser-AgentAccept-Encoding……哪怕内容几乎一模一样。
100 个请求?光头部就可能传走几十 KB。

HTTP/2 用 HPACK 压缩头部。客户端和服务器各自维护一张动态表,把高频字段(比如 :method: GET:path: /main.css)映射成短索引。第一次传全量,后面只传几个字节的编号。
有个资讯类站点实测:单次请求头部从平均 500 字节压到 30 字节左右,整体请求头流量大幅下降。对手机用户特别明显——移动网络延迟高、包容易丢,少传点没用的字节,就是少一次重传、少一点等待。

还有个博客,首页加载了 50 多个第三方追踪脚本。HTTP/1.1 下,这些脚本的请求头加起来占了总流量的近一半;切到 HTTP/2 后,这部分直接砍掉大半,首屏加载快得连运营都注意到“广告位出得更及时了”。

服务端推送是真香还是坑?

服务端推送(Server Push)听起来很美:浏览器要 HTML,服务器顺手把 CSS 和 JS 也“推”过去,省得再发一次请求。
但现实是,它很容易推错、推多、推重复。

我见过一个团队,首页一打开,就把整个 SPA 的所有 chunk 全推给用户。结果用户只看了首页就关掉页面,其他 JS 完全没用上,白白占带宽。更糟的是,如果浏览器缓存里已经有那个 CSS,推送的数据就成了无效噪音,还可能阻塞后续真正需要的响应。

真正稳妥的做法是:只推那些确定会被用到、且大概率没缓存的资源。比如某个内部工具站,用户登录后首次访问,服务器只推送核心 UI 组件 + 登录态校验脚本——这两个文件每次都会用,又很少命中本地缓存,推得准,收益才实在。

如果你拿不准该推什么,那就先别推。HTTP/2 的多路复用本身已经足够高效,服务端推送不是必需项。事实上,Cloudflare、阿里云 CDN 等主流平台现在默认关闭推送,理由很实在:收益难量化,风险却很具体。

升级 HTTP/2 需要改代码吗?

不需要改一行业务代码。
前端不用动,后端不用重构,数据库不用迁移。HTTP/2 是传输层升级,对应用层完全透明。

你真正要做的只有三件事:

  1. 确认服务器版本:Nginx ≥ 1.9.5、Apache ≥ 2.4.17、IIS 10+ 都原生支持;云厂商的负载均衡(如阿里云 SLB、腾讯云 CLB)也都支持配置。
  2. 确保用了 HTTPS:Chrome/Firefox/Safari 只对加密连接启用 HTTP/2,所以你得有一张有效的 SSL 证书。Let’s Encrypt 的免费证书就够用。
  3. 加一行配置:Nginx 在 server 块里把 listen 443 ssl; 改成 listen 443 ssl http2;;Apache 加上 Protocols h2 http/1.1

我帮一个用 Nginx 1.18 搭建的小型博客升级,只改了监听配置,nginx -s reload 重启,Chrome Network 里 Protocol 列立刻变成 h2。全程没停服务,用户毫无感知。

升级后还有哪些坑要避开?

HTTP/2 快,但有些 HTTP/1.1 时代的老习惯,现在反而会拖后腿:

别再合并 JS/CSS 文件了
以前为减少请求数,常把十几个 CSS 合成一个 all.css。HTTP/2 下,这种做法弊大于利:一个小改动导致整个大文件缓存失效,用户得重新下载全部样式。现在建议保持文件粒度合理,让多路复用并行加载,也让浏览器能更精准地复用缓存。

停用域名分片(Domain Sharding)
如果你还在用 static1.example.comstatic2.example.com 分散资源,赶紧收回来。HTTP/2 不支持跨域名复用连接,每个子域名都会新建独立连接,等于主动放弃多路复用。统一回主域名,或用 CDN 提供的单一加速域名。

检查服务器并发能力
HTTP/2 把压力从“连接数”转移到“单连接并发处理能力”。如果 PHP-FPM 进程太少、Node.js 事件循环太忙、或者 Nginx worker_connections 没调够,单个连接里堆太多请求,反而会堵住。上线前建议用 abwrk 做一轮简单压测,适当调高 pm.max_childrenworker_connections

现在怎么开始升级?

别等排期、别写方案,今天下班前就能做完。

第一步:确认基础条件

  • 登服务器,运行 nginx -vhttpd -v,看版本是否达标。不达标就更新:Ubuntu/Debian 用 sudo apt update && sudo apt install nginx,CentOS 用 sudo yum update httpd
  • 运行 openssl s_client -connect yourdomain.com:443 2>/dev/null | grep "Verify return code",确认 SSL 证书有效。没证书?直接运行 sudo certbot --nginx(Nginx)或 sudo certbot --apache(Apache),Certbot 会自动申请并配置。

第二步:改一行配置

  • Nginx 用户:打开你的站点配置文件(通常在 /etc/nginx/sites-enabled/ 下),找到 listen 443 ssl; 这行,改成 listen 443 ssl http2;
  • Apache 用户:在 ssl.conf 或虚拟主机配置里,加上 Protocols h2 http/1.1
  • 保存后,执行 sudo nginx -s reloadsudo systemctl restart httpd

第三步:立刻验证

  • 打开 Chrome,F12 → Network → 刷新页面 → 看 Protocol 列是不是显示 h2
  • 顺手打开 KeyCDN HTTP/2 Test(纯前端检测,无需注册),输域名,几秒出结果。

整个过程不到 20 分钟。今晚改完,明早用户刷页面时,不会看到任何提示,但会下意识觉得:“咦,好像比以前顺了?”——这就够了。