Nginx 不主动识别协议版本,但通过 $server_protocol 变量可实现协议感知的静态资源差异化处理,如缓存策略、资源后缀选择及日志记录,并需注意 CDN 回源和 HTTPS 限制等边界条件。

Nginx 本身不主动“识别”协议版本来改变静态资源服务逻辑,但它能准确记录并暴露请求所用的协议(HTTP/1.1、HTTP/2.0 等),供你基于此做条件判断或日志分析。静态资源服务(如 location /static/)默认对所有协议一视同仁,但你可以利用 $server_protocol 变量实现协议感知的差异化处理。
静态资源路径中直接使用 $server_protocol
你可以在 alias、root 或响应头中引用 $server_protocol,实现协议相关的路径切换或标记:
-
协议区分缓存策略
HTTP/2 客户端通常更可靠,可设更长缓存;HTTP/1.1 客户端可能有老旧代理,缓存需更保守:map $server_protocol $cache_max_age { "HTTP/2.0" "31536000"; default "86400"; } location /static/ { alias /var/www/static/; expires $cache_max_age; add_header X-Protocol $server_protocol; } -
协议相关资源目录(较少见,但可行)
比如为 HTTP/2 提供预压缩的.br文件(需配合ngx_brotli),而 HTTP/1.1 回退到.gz:map $server_protocol $static_suffix { "HTTP/2.0" ".br"; default ".gz"; } location ~ \.js$ { add_header Content-Encoding br; try_files $uri$static_suffix =404; }注意:这要求文件已预先生成对应后缀,且客户端支持相应编码。
日志中精准捕获协议信息,用于后续分析
静态资源请求的协议版本必须显式记入 access log,否则无法统计或告警:
log_format proto_log '$remote_addr [$time_local] "$request_method $uri" $status $body_bytes_sent "$http_user_agent" $server_protocol'; access_log /var/log/nginx/static-access.log proto_log;
这样每条日志末尾都会带 HTTP/1.1 或 HTTP/2.0,方便用 awk、Loki 或 ELK 按协议筛选 /static/ 请求,例如:
# 统计 HTTP/2 下最热的静态资源
awk '$NF == "HTTP/2.0" && $4 ~ /^"GET \/static\// {print $4}' static-access.log | sort | uniq -c | sort -nr | head -10协议识别的边界与注意事项
-
$server_protocol反映的是Nginx 与客户端之间协商的实际协议,不是配置里写的“支持哪些”。它真实、轻量、无需额外模块。 - CDN 回源时,
$server_protocol是 CDN 到 Nginx 的协议(通常是 HTTP/1.1),不是原始客户端协议。如需真实客户端协议,需 CDN 注入自定义 Header(如X-Forwarded-Proto: h2)并用$http_x_forwarded_proto判断。 - HTTP/2 必须走 HTTPS(TLS),所以
$server_protocol == "HTTP/2.0"意味着该请求一定经过 TLS 握手。可同步记录$ssl_protocol和$ssl_cipher,排查是否因 ALPN 协商失败导致降级。
不复杂但容易忽略


















