ALPN 是什么
ALPN(应用层协议协商)让客户端在 TLS 握手阶段就声明想用的上层协议(h2、http/1.1、h3),服务器从中选择一个并在握手中确认,从而省掉一次额外的探测往返。浏览器访问 HTTPS 站点时会带上 ALPN,服务器没选到 h2 就自动回落 http/1.1——「HTTP/2 明明开了却没生效」通常要在这一层找原因。
基本信息
| 作用 | 在 TLS 握手中商定上层应用协议 |
|---|---|
| 常见取值 | h2、http/1.1、h3(HTTP/3 走 QUIC) |
| 规范 | RFC 7301(ALPN)、RFC 9113(HTTP/2) |
| 协议位置 | ClientHello 与 ServerHello 的 ALPN 扩展 |
| 回落行为 | 服务器未选择时客户端退回 http/1.1 |
| Nginx 相关 | 需启用 http2 参数,且要使用支持 ALPN 的版本 |
典型使用场景
- 确认站点是否真正启用 HTTP/2:看 ALPN 是否协商出 h2
- 排查 CDN 与回源链路:边缘与源站各自可能协商出不同协议
- 压测与兼容性测试:显式指定 ALPN 值验证服务端行为
- 排查老客户端兼容问题:不支持 ALPN 的客户端能否正常回落
- 规划 HTTP/3:确认客户端与服务端是否都声明 h3
测试 ALPN 协商
测试 ALPN 协商
# 显式请求 h2,看服务端是否接受
openssl s_client -connect example.com:443 -alpn h2 </dev/null 2>/dev/null | grep -i alpn
# 用 curl 观察实际协商到的协议
curl -v --http2 https://example.com 2>&1 | grep -i -E 'ALPN|HTTP/2'
curl -sI --http2 https://example.com | head -1
# 同时声明多个协议,验证服务端的选择顺序
openssl s_client -connect example.com:443 -alpn 'h2,http/1.1' </dev/null 2>/dev/null | grep -i alpn
# 检查 Nginx 配置中的 http2 参数
nginx -T 2>/dev/null | grep -n 'http2'协议标识读法
| 标识 | 含义 | 端口与传输 |
|---|---|---|
| h2 | HTTP/2 over TLS | 443 走 TCP |
| http/1.1 | HTTP/1.1 | 443 走 TCP |
| h3 | HTTP/3 over QUIC | 443 走 UDP |
| 未协商到 | 服务端未选择或未配置 | 客户端回落 http/1.1 |
HTTP/2 的双向流与多路复用建立在 TLS 之上,客户端必须通过 ALPN 声明 h2 才能启用;只要服务端没有在握手中确认 h2,浏览器就会安静地退回 HTTP/1.1,页面依然可用,因此这个问题容易被长期忽略。
调整 ALPN 或协议版本属于「看起来无害」的改动,但会影响所有客户端:上线前用真实客户端验证(浏览器、curl、移动端 SDK),避免出现特定客户端握手失败的情况。
HTTP/3 的协商方式与 h2 不同:它跑在基于 UDP 的 QUIC 上,同样用 ALPN 声明 h3 标识,端口仍是 443。实践中常在同一个域名上同时提供 h3 与 h2,由客户端自行选择,因此防火墙必须放行 UDP 443,否则 h3 永远不会生效。