$server_protocol能准确区分http/1.1和http/2,因其直接记录tls握手阶段alpn协商结果,值为“http/1.1”或“http/2.0”,真实反映每次请求实际使用的协议,不受ua推测、代理透传或客户端检测干扰,是服务端日志中唯一端到端可信的协议标识。

$server_protocol 是 Nginx 日志中一个内置变量,用于记录客户端发起请求时所使用的 HTTP 协议版本(如 HTTP/1.1 或 HTTP/2.0)。它不表示服务器“支持”什么协议,而是真实反映该次请求实际协商并使用的协议版本,因此是统计线上真实 HTTP/1.1 与 HTTP/2 使用率最直接、最可靠的依据。
为什么 $server_protocol 能准确区分 HTTP/1.1 和 HTTP/2?
Nginx 在 TLS 握手阶段通过 ALPN(Application-Layer Protocol Negotiation)协商协议:
- 若客户端支持且服务端配置了
http2,且使用 HTTPS(绝大多数现代部署场景),则协商成功后该请求走 HTTP/2; - 否则回落至 HTTP/1.1(包括不支持 ALPN 的旧客户端、未启用 http2 的 server 块、或明文 HTTP 请求)。
$server_protocol 正是这一协商结果的字符串快照,值为:
-
"HTTP/1.1" -
"HTTP/2.0"(注意:Nginx 固定输出HTTP/2.0,而非HTTP/2;RFC 中二者等价)
✅ 关键点:它不受
User-Agent推测干扰,不依赖 JS 检测,也不受代理层篡改——只要日志由 Nginx 原生记录,就具备端到端可信度。
如何在 access_log 中启用并提取协议信息?
1. 确保日志格式包含 $server_protocol
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$server_protocol'; // ← 添加此项
access_log /var/log/nginx/access.log main;
重启 Nginx 后,日志行末尾将出现类似:
192.168.1.100 - - [11/May/2026:22:45:32 +0000] "GET /index.html HTTP/1.1" 200 1245 "-" "Mozilla/5.0..." HTTP/1.1 192.168.1.101 - - [11/May/2026:22:45:33 +0000] "GET /app.js HTTP/2.0" 200 87232 "-" "Chrome/124..." HTTP/2.0
2. 统计使用率(Linux 命令示例)
# 统计最近 10 万行中各协议占比
tail -100000 /var/log/nginx/access.log | \
awk '{print $12}' | \
sort | uniq -c | sort -nr
# 输出示例:
# 68243 HTTP/2.0
# 31757 HTTP/1.1
? 提示:字段序号取决于你的
log_format。用awk '{print NF; exit}'查看总字段数,再结合空格分隔定位$server_protocol所在列(通常为倒数第 1 或第 2 位)。
注意事项:哪些情况会导致 $server_protocol 不反映真实意图?
-
HTTP/1.1 明文请求(非 HTTPS):Nginx 默认不为
http://启用 HTTP/2(浏览器也不支持),所以这类请求永远记为HTTP/1.1—— 这是正确行为,不是误差。 -
反向代理透传问题:若前端有 CDN 或负载均衡器(如 Cloudflare、AWS ALB),且它终止 TLS 并以 HTTP/1.1 转发给 Nginx,则
$server_protocol显示HTTP/1.1,但用户实际走的是 HTTP/2。此时需依赖 CDN 自身日志或X-Forwarded-Proto+X-Forwarded-For组合判断。 -
Nginx 版本过低或未启用 http2:确认配置中有
listen 443 ssl http2;,且 Nginx ≥ 1.9.5(推荐 ≥ 1.19.0)。
补充:对比其他识别方式的局限性
| 方法 | 是否可靠 | 原因 |
|---|---|---|
检查 User-Agent 是否含 “Chrome/120+” |
❌ 不可靠 | 旧 UA 可能支持 HTTP/2;新 UA 可能被降级 |
查看响应头是否有 alt-svc
|
❌ 仅提示能力,非实际使用 | |
用 curl -I --http2 https://site.com 测试 |
❌ 单点探测,无法代表全量用户 | |
| 依赖浏览器 DevTools → Network → Protocol 列 | ❌ 仅限开发者手动观察,不可规模化 |
只有 $server_protocol 是服务端对每一次真实请求的客观记录,天然适配日志分析、BI 看板、A/B 测试归因等生产场景。
不复杂但容易忽略:确保日志格式写对字段、确认 HTTPS 配置生效、区分边缘代理的影响,就能用好这个变量。










