nginx静态缓存导致后端拿不到原始user-agent,根本原因是缓存键(proxy_cache_key)与vary头不匹配、proxy_set_header错误覆盖ua、或请求命中缓存未触达后端;需统一缓存键含$http_user_agent、禁用错误header重写、并用x-upstream-cache-status验证命中状态。

开启静态化缓存后,后端拿不到原始 User-Agent,不是缓存“吃掉”了它,而是 Nginx 在缓存决策与请求透传两个环节中,对请求头的处理逻辑被默认行为覆盖——尤其当 Vary、proxy_set_header 和缓存键生成机制未对齐时,原始 UA 会在抵达后端前就已不可见。
确认 Vary 头是否真正生效且匹配缓存键
若 Nginx 配置了 proxy_cache_key $scheme$host$request_uri,但又设置了 Vary: User-Agent,则两者矛盾:Vary 声明 UA 影响响应差异,缓存键却没包含它,Nginx 会降级忽略 Vary 或复用错误副本,导致后端实际收到的请求可能来自其他 UA 的缓存体,而非原始请求。
- 检查后端日志中实际收到的
User-Agent是否与客户端发起的一致(可加log_format full '$http_user_agent';) - 在对应 location 中显式定义缓存键,确保含 UA:
proxy_cache_key "$scheme$host$request_uri $http_user_agent"; - 避免滥用
Vary: User-Agent;如仅需区分移动端/桌面端,建议用map归一化:
map $http_user_agent $ua_type {
~*android|iphone "mobile";
default "desktop";
}
再用$ua_type参与proxy_cache_key和Vary
排查 proxy_set_header 是否覆盖或清空了原始 UA
Nginx 默认不自动透传所有请求头,User-Agent 属于“非标准透传头”,若配置了 proxy_set_header User-Agent ... 却写错变量(如误用 $user_agent 而非 $http_user_agent),就会把值设为空或固定字符串。
- 确认未出现类似
proxy_set_header User-Agent "";或proxy_set_header User-Agent $upstream_http_user_agent;这类错误写法 - 正确写法应为:
proxy_set_header User-Agent $http_user_agent; - 若上游服务依赖 UA 做设备识别,建议同时透传
Accept、Sec-CH-UA等现代 UA 相关头,并启用underscores_in_headers on;防止带下划线的 UA 扩展头被丢弃
验证缓存命中路径是否绕过了 header 透传逻辑
当请求命中缓存(HIT 或 STALE)时,Nginx 不会再次向后端发起代理请求,也就不会执行 proxy_set_header 指令——但此时返回给客户端的内容,是之前缓存下来的完整响应(含响应头),而**后端根本没参与这次响应生成**。所以你看到“后端拿不到 UA”,本质是:这次请求压根没到后端。
- 用
curl -I http://your-domain/查看响应头中的X-Cache或X-Upstream-Cache-Status,确认是否为HIT - 若需每次让后端都收到原始 UA(例如做 AB 测试或风控),不应依赖缓存穿透,而应改用
proxy_cache_bypass $arg_nocache或基于 UA 动态跳过缓存:
set $skip_cache 0;
if ($http_user_agent ~* "bot|crawler") { set $skip_cache 1; }
proxy_cache_bypass $skip_cache;











