# ALPN（应用层协议协商）是什么？定义、例子与常见误区

> ALPN 是一个 TLS 扩展，让客户端和服务器在握手过程中直接商定上层协议，例如 h2 或 http/1.1，不需要额外往返。

Source: https://ssl.sh/zh/glossary/alpn/
Last updated: 2026-11-10

ALPN 由 [RFC 7301](https://www.rfc-editor.org/rfc/rfc7301) 定义。客户端在 ClientHello 里列出自己支持的协议标识，如 `h2`、`http/1.1`，服务器从中选一个返回。TLS 1.3 中服务器的选择放在加密的 EncryptedExtensions 消息里，但客户端的候选列表仍在明文的 ClientHello 中。

## 为什么重要
浏览器只有在通过 ALPN 协商成功时才会使用 HTTP/2，否则自动退回 HTTP/1.1。所以“后端明明开了 HTTP/2，浏览器还是 1.1”的常见原因，是前面的反向代理或负载均衡没有通告 `h2`。基于 [QUIC](https://ssl.sh/zh/glossary/quic/) 的 HTTP/3 用的标识是 `h3`。ACME 的 [TLS-ALPN-01](https://ssl.sh/zh/glossary/tls-alpn-01/) 验证也建立在 ALPN 之上：CA 以 `acme-tls/1` 协议发起连接，服务器返回专门的验证证书，而不是平时的站点证书。按 RFC 7301，服务器一个候选协议都不支持时，应当以 `no_application_protocol` 告警中止握手，而不是等到 HTTP 层再出错。

## 例子
```bash
openssl s_client -connect example.com:443 -servername example.com -alpn h2,http/1.1 </dev/null 2>/dev/null | grep -i alpn
# ALPN protocol: h2
```

在 Nginx 中，较新版本用 `http2 on;`，旧版本用 `listen 443 ssl http2;` 开启 HTTP/2，对应的 ALPN 值就是 `h2`。

## 常见误区
- **ALPN 用来协商 TLS 版本。** 不是。TLS 版本和密码套件有各自的协商机制，ALPN 只决定 TLS 之上跑什么协议。
- **ALPN 和 NPN 是一回事。** NPN 是早期由 Google 提出、由客户端选择协议的扩展，已被由服务器做选择的 ALPN 取代。
- **应用里开了 HTTP/2 就够了。** 如果前面负责 [TLS 终止](https://ssl.sh/zh/glossary/tls-termination/) 的代理没有通告 `h2`，客户端依然只会用 HTTP/1.1。

## 相关术语

- [TLS 握手](https://ssl.sh/zh/glossary/tls-handshake/): TLS 握手是 TLS 连接开始时的一组消息交换，客户端与服务器在其中协商协议版本和密码套件、验证服务器身份并派生会话密钥。
- [SNI](https://ssl.sh/zh/glossary/sni/): SNI 是 TLS 的一个扩展，客户端在 ClientHello 中写明要访问的域名，使同一个 IP 能为多个 HTTPS 站点分别返回各自的证书。
- [QUIC](https://ssl.sh/zh/glossary/quic/): QUIC 是基于 UDP、始终加密的传输协议，把 TLS 1.3 握手内置在传输层中，HTTP/3 就运行在它之上。
- [TLS-ALPN-01](https://ssl.sh/zh/glossary/tls-alpn-01/): TLS-ALPN-01 是一种 ACME 验证方式，服务器在 443 端口针对 acme-tls/1 协议出示一张特殊证书来证明域名控制权。
- [TLS 1.3](https://ssl.sh/zh/glossary/tls-1-3/): TLS 1.3 是当前最新的传输层安全协议版本（2018 年的 RFC 8446，现行规范为 RFC 9846），完整握手只需一个往返，且只保留 AEAD 加密算法。
- [TLS 终止](https://ssl.sh/zh/glossary/tls-termination/): TLS 终止是指网络路径上客户端 TLS 连接结束并被解密的位置，可以是 CDN 边缘、负载均衡、反向代理，也可以是应用服务器本身。
