如何利用 log_format 实现对 $http_sec_ch_ua 的配置以监控现代浏览器Client Hints?
- 内容介绍
- 文章标签
- 相关推荐
本文共计797个文字,预计阅读时间需要4分钟。
无法直接使用 `$http_sec_ch_ua` 记录 Sec-CH-UA 头部信息,因为 Nginx 默认不解析或暴露 Client Hints 类请求头 - 它不属于标准 HTTP 头部字段白名单。需显式启用才能在 `log_format` 中使用。
为什么 $http_sec_ch_ua 在 log_format 中为空或不生效
Nginx 对以 Sec- 开头的客户端提示头(如 Sec-CH-UA、Sec-CH-UA-Mobile、Sec-CH-UA-Platform)默认忽略,除非满足两个前提:
- Nginx 版本 ≥ 1.21.6(支持
underscores_in_headers on及更宽松的 header 解析); - 客户端实际发送了该头部(仅 Chromium 101+、Edge 101+、Opera 87+ 等现代浏览器在开启相关权限策略后才发送,且需页面主动发起
accept-ch声明); - 请求未被中间代理(如 CDN、WAF)剥离 Sec-CH-* 头部(很多 CDN 默认过滤这类非标准头)。
正确配置步骤:启用 + 映射 + 记录
分三步操作,缺一不可:
-
在 http 块中启用非标准头解析:
underscores_in_headers on;
(允许带连字符的 header 名被识别为变量,否则$http_sec_ch_ua永远为空) -
定义映射变量(推荐,更稳定):
map $sent_http_vary $ch_ua {<br> ~"Sec-CH-UA" $http_sec_ch_ua;<br> default "-";<br> }
或更直接地(Nginx ≥ 1.19):set $ch_ua $http_sec_ch_ua;
(避免因空值导致日志格式错位) -
在 log_format 中引用:
log_format client_hints '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_user_agent" ' '"$ch_ua" "$http_sec_ch_ua_mobile" "$http_sec_ch_ua_platform"';
然后在 server 或 location 块中启用:access_log /var/log/nginx/ch-hints.log client_hints;
验证是否真能采集到数据
仅靠配置不等于有数据。需同步确认:
- 前端页面已通过
<meta http-equiv="Accept-CH" content="Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform">或响应头Accept-CH: Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform主动声明需求; - 使用 Chrome/Edge 访问时打开 DevTools → Network → 刷新请求 → 查看 Request Headers 是否含
sec-ch-ua字段(注意大小写:实际发送是小写sec-ch-ua,Nginx 内部转为下划线形式$http_sec_ch_ua); - 检查 Nginx error.log 是否报
unknown "http_sec_ch_ua" variable—— 若有,说明未启用underscores_in_headers on或版本过低。
替代方案:当 Sec-CH-UA 不可用时的兜底策略
Client Hints 并非全量覆盖,尤其 Safari(不支持)、旧版 Chrome(
- 原始
$http_user_agent(用于兼容回溯); - 解析后的结构化字段(如用 Lua 模块或外部日志处理器提取 browser_name、os、is_mobile);
- 关键 Client Hints 字段(
$http_sec_ch_ua_mobile是布尔信号,比 UA 更可靠判断是否移动设备)。
本文共计797个文字,预计阅读时间需要4分钟。
无法直接使用 `$http_sec_ch_ua` 记录 Sec-CH-UA 头部信息,因为 Nginx 默认不解析或暴露 Client Hints 类请求头 - 它不属于标准 HTTP 头部字段白名单。需显式启用才能在 `log_format` 中使用。
为什么 $http_sec_ch_ua 在 log_format 中为空或不生效
Nginx 对以 Sec- 开头的客户端提示头(如 Sec-CH-UA、Sec-CH-UA-Mobile、Sec-CH-UA-Platform)默认忽略,除非满足两个前提:
- Nginx 版本 ≥ 1.21.6(支持
underscores_in_headers on及更宽松的 header 解析); - 客户端实际发送了该头部(仅 Chromium 101+、Edge 101+、Opera 87+ 等现代浏览器在开启相关权限策略后才发送,且需页面主动发起
accept-ch声明); - 请求未被中间代理(如 CDN、WAF)剥离 Sec-CH-* 头部(很多 CDN 默认过滤这类非标准头)。
正确配置步骤:启用 + 映射 + 记录
分三步操作,缺一不可:
-
在 http 块中启用非标准头解析:
underscores_in_headers on;
(允许带连字符的 header 名被识别为变量,否则$http_sec_ch_ua永远为空) -
定义映射变量(推荐,更稳定):
map $sent_http_vary $ch_ua {<br> ~"Sec-CH-UA" $http_sec_ch_ua;<br> default "-";<br> }
或更直接地(Nginx ≥ 1.19):set $ch_ua $http_sec_ch_ua;
(避免因空值导致日志格式错位) -
在 log_format 中引用:
log_format client_hints '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_user_agent" ' '"$ch_ua" "$http_sec_ch_ua_mobile" "$http_sec_ch_ua_platform"';
然后在 server 或 location 块中启用:access_log /var/log/nginx/ch-hints.log client_hints;
验证是否真能采集到数据
仅靠配置不等于有数据。需同步确认:
- 前端页面已通过
<meta http-equiv="Accept-CH" content="Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform">或响应头Accept-CH: Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform主动声明需求; - 使用 Chrome/Edge 访问时打开 DevTools → Network → 刷新请求 → 查看 Request Headers 是否含
sec-ch-ua字段(注意大小写:实际发送是小写sec-ch-ua,Nginx 内部转为下划线形式$http_sec_ch_ua); - 检查 Nginx error.log 是否报
unknown "http_sec_ch_ua" variable—— 若有,说明未启用underscores_in_headers on或版本过低。
替代方案:当 Sec-CH-UA 不可用时的兜底策略
Client Hints 并非全量覆盖,尤其 Safari(不支持)、旧版 Chrome(
- 原始
$http_user_agent(用于兼容回溯); - 解析后的结构化字段(如用 Lua 模块或外部日志处理器提取 browser_name、os、is_mobile);
- 关键 Client Hints 字段(
$http_sec_ch_ua_mobile是布尔信号,比 UA 更可靠判断是否移动设备)。

