如何通过 $server_protocol 变量在监控日志中精准识别并分类 HTTP/1.1 与 HTTP/2 的路径请求

作者:袖梨 2026-06-20
$server_protocol 是 Nginx 记录客户端请求协议版本的内置变量,值为 HTTP/1.0、HTTP/1.1 或 HTTP/2.0,是区分 HTTP 版本最可靠且低开销的依据,但 CDN 回源时可能不反映真实客户端协议。

$server_protocol 是 Nginx 内置变量,用于记录客户端发起请求时使用的协议版本(如 HTTP/1.1HTTP/2.0),它在 access log 中可直接输出,是区分 HTTP/1.x 与 HTTP/2 请求最可靠、开销最小的依据。

确认 $server_protocol 的实际取值格式

Nginx 中该变量返回的是协议字符串,常见值包括:

  • HTTP/1.0
  • HTTP/1.1
  • HTTP/2.0(注意:即使客户端使用 HTTP/2,Nginx 也统一记为 HTTP/2.0,而非 h2

可通过临时添加日志字段验证:

log_format debug_log '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$server_protocol"';

在 access log 中结构化记录协议类型

推荐将协议信息作为独立字段写入日志,便于后续解析与筛选。例如:

log_format http_version '$remote_addr [$time_local] "$request_method $uri $server_protocol" $status $body_bytes_sent $request_time "$http_user_agent" $server_protocol';

这样每条日志末尾都明确标注协议,无需解析 request line,避免因 URI 中含空格或特殊字符导致误切分。

用日志分析工具按协议分类统计路径请求

以常见工具为例:

  • grep + awk:提取所有 HTTP/2 请求的路径(URI)并去重统计
    awk '$NF == "HTTP/2.0" {print $4}' access.log | sort | uniq -c | sort -nr
  • ELK / Grafana Loki:在日志采集时通过 parser 提取 protocol 字段(正则:"(?P<protocol>HTTP/[0-9].[0-9])"$),再用 KQL 或 LogQL 按 protocol : "HTTP/2.0" 过滤,并聚合 uripath
  • Prometheus + nginx-exporter:原生不暴露协议维度,需配合自定义 log export(如 logstash 或 vector)将 $server_protocol 转为 label,再构建 nginx_http_requests_total{protocol="HTTP/2.0", path="/api/v1/users"} 类型指标

注意 TLS 和协议协商的实际影响

HTTP/2 在 Nginx 中仅支持通过 HTTPS 启用(RFC 7540 要求),因此若看到 $server_protocol == "HTTP/2.0",必对应 TLS 连接;而 HTTP/1.1 可能来自 HTTP 或 HTTPS。这意味着:

  • 不能仅靠 $scheme(http/https)判断协议版本
  • 若需关联性能分析,建议同时记录 $ssl_protocol$ssl_cipher,排查是否因 TLS 版本或 ALPN 协商失败导致降级到 HTTP/1.1
  • 某些 CDN(如 Cloudflare)可能将 HTTP/2 终止在其边缘,回源仍为 HTTP/1.1 —— 此时 Nginx 收到的是 HTTP/1.1$server_protocol 不反映客户端真实协议,需结合 $http_upgrade 或 CDN 自定义 header 判断

相关文章

精彩推荐