为什么 HTTP/2 必须搭配 HTTPS
HTTP/2 协议本身支持明文传输(h2c),但几乎所有主流浏览器都只实现基于 TLS 的 HTTP/2(h2)。这不是偶然——HTTP/2 的多路复用、头部压缩等特性在明文环境下容易受到中间人攻击和协议降级攻击。因此,部署 HTTP/2 的第一步就是确保 HTTPS 配置正确且高效。
但 HTTPS 本身会引入 TLS 握手开销。如果配置不当,HTTP/2 的性能优势可能被 TLS 的额外延迟抵消。下面从协议层到服务器配置,逐步拆解优化要点。
一、TLS 层优化:为 HTTP/2 铺路
1. 启用 TLS 1.3
TLS 1.3 将握手从两次往返(2-RTT)压缩到一次往返(1-RTT),会话恢复时甚至可以实现 0-RTT。对于 HTTP/2 的多路复用场景,更快的握手意味着连接能更早进入数据传输阶段。
在 Nginx 中启用 TLS 1.3:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
注意:TLS 1.3 下 ssl_ciphers 的配置不再生效,密码套件由 OpenSSL 自动协商。ssl_prefer_server_ciphers 建议设为 off,让客户端选择更优的套件。
2. 配置 OCSP Stapling
浏览器在 TLS 握手时需要验证服务器证书是否被吊销。传统方式是浏览器自己去访问 CA 的 OCSP 服务器,这会增加一个额外的网络请求。OCSP Stapling 让服务器在握手时直接附带吊销状态证明,省去这个往返。
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
resolver 8.8.8.8 1.1.1.1 valid=300s;
3. 会话复用
TLS 会话复用可以跳过完整的握手过程。TLS 1.3 使用 PSK(预共享密钥)恢复,TLS 1.2 则依赖 Session ID 或 Session Ticket。在 Nginx 中:
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets on;
shared:SSL:10m 大约能存储 40000 个会话,对于大多数站点足够。
二、HTTP/2 层优化:发挥多路复用优势
1. 启用 HTTP/2
listen 443 ssl http2;
如果使用 Nginx 1.25.1 以上版本,推荐使用新语法:
listen 443 ssl;
http2 on;
2. 调整并发流与窗口大小
HTTP/2 的多路复用允许在同一连接上并行传输多个请求。但服务器对并发流数量有限制,窗口大小也会影响吞吐量。
http2_max_concurrent_streams 128;
http2_chunk_size 8k;
http2_max_concurrent_streams 默认值通常为 128,对于图片较多的站点可以适当提高。但注意:过高的并发流会消耗服务器内存,建议根据实际负载测试后调整。
3. 头部压缩与 HPACK
HTTP/2 使用 HPACK 算法压缩头部。虽然 Nginx 没有直接暴露 HPACK 的调优参数,但可以通过减少冗余头部来间接优化。例如:
- 移除不必要的
X-Powered-By、Server等头部 - 避免在 Cookie 中存储过多数据(Cookie 会随每个请求发送)
- 使用
http2_push_preload配合Link头部实现资源推送
4. 服务器推送的取舍
HTTP/2 的 Server Push 曾被视为革命性特性,但实践表明它容易推送浏览器已缓存的资源,反而浪费带宽。Chrome 已在 106 版本后移除对 HTTP/2 Push 的支持。当前建议是:不要依赖 Server Push,改用 preload 提示。
add_header Link "</css/main.css>; rel=preload; as=style";
add_header Link "</js/app.js>; rel=preload; as=script";
三、连接层优化:减少握手次数
1. 启用 HSTS
HSTS(HTTP Strict Transport Security)强制浏览器使用 HTTPS,避免首次访问时的 HTTP 跳转。更重要的是,HSTS 允许浏览器缓存 HTTPS 状态,后续访问直接走 TLS。
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
max-age=63072000 表示两年。preload 标记可以申请加入浏览器预加载列表,但需谨慎——一旦加入,移除需要数月时间。
2. 使用 Alt-Svc 引导 HTTP/3
虽然本文聚焦 HTTP/2,但 HTTP/3 基于 QUIC 协议,在弱网环境下表现更好。可以通过 Alt-Svc 头部告知浏览器 HTTP/3 端点,实现平滑升级:
add_header Alt-Svc 'h3=":443"; ma=86400';
浏览器首次仍走 HTTP/2,后续请求尝试 HTTP/3。这不会影响现有 HTTP/2 连接的性能。
四、实战配置示例
以下是一个兼顾 HTTP/2 与 HTTPS 性能的 Nginx 配置片段:
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets on;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
resolver 8.8.8.8 1.1.1.1 valid=300s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header Alt-Svc 'h3=":443"; ma=86400';
http2_max_concurrent_streams 128;
http2_chunk_size 8k;
location / {
root /var/www/html;
index index.html;
}
}
五、验证与监控
配置完成后,用以下工具验证:
- curl:
curl -I --http2 https://example.com查看是否返回HTTP/2 200 - Chrome DevTools:Network 面板中 Protocol 列显示
h2即表示 HTTP/2 生效 - SSL Labs:测试 TLS 配置评分,目标为 A 或 A+
- WebPageTest:对比优化前后的首字节时间(TTFB)和开始渲染时间
监控方面,重点关注 TLS 握手时间、HTTP/2 流重置率、以及服务器 CPU 在 TLS 加解密上的开销。如果 CPU 成为瓶颈,可以考虑启用硬件加速或使用更高效的密码套件。
总结
HTTP/2 与 HTTPS 的结合不是简单的“开启开关”,而是一套从 TLS 握手到流控制的系统性优化。核心思路是:用 TLS 1.3 和会话复用降低握手成本,用合理的并发流和头部策略发挥多路复用优势,用 HSTS 和 Alt-Svc 减少连接建立的开销。每一步都需要根据实际流量特征测试调整,没有放之四海而皆准的参数。建议从 TLS 1.3 和 OCSP Stapling 入手,这两项改动风险低、收益明显,之后再逐步调优 HTTP/2 的流参数。
未经允许不得转载:任鹏个人博客 » HTTP/2 与 HTTPS 结合下的性能优化实战


朋友圈点赞图在线生成源码