根本原因是add_header为静态指令,不支持运行时变量插值,$upstream_cache_status仅在proxy_pass后的location中有效且需配合proxy_hide_header才能正确注入;其值包括HIT、MISS、BYPASS、EXPIRED、STALE等固定枚举。

add_header 不能动态设置 X-Cache-Status 的根本原因
add_header 是静态指令,Nginx 在配置加载阶段就完成 header 注入,无法感知请求时的缓存状态(如 HIT、MISS、BYPASS)。直接写 add_header X-Cache-Status $upstream_cache_status; 看似合理,但实际会输出字面量 $upstream_cache_status 字符串,而非变量值——因为 add_header 不支持运行时变量插值(仅部分内置变量在特定上下文可用,且 $upstream_cache_status 不在此列)。
必须用 proxy_hide_header + add_header 组合绕过限制
真正可行的方案是:先屏蔽上游响应中可能已存在的 X-Cache-Status(避免冲突),再用 add_header 注入 Nginx 自己计算出的状态。关键在于——$upstream_cache_status 只有在 proxy_pass 后的 location 块中才有效,且必须配合 proxy_hide_header 防止被覆盖。
- 在
location块内添加proxy_hide_header X-Cache-Status; - 紧接着写
add_header X-Cache-Status $upstream_cache_status; - 确保该 location 确实启用了缓存(即配置了
proxy_cache和proxy_cache_valid) - 若使用了
proxy_cache_bypass或proxy_no_cache,$upstream_cache_status仍会正确反映最终决策(如BYPASS或MISS)
前端看到的值和真实含义要对得上
返回的 X-Cache-Status 值不是随便写的,Nginx 有固定枚举:
-
HIT:响应直接从本地缓存读取,未发请求到后端 -
MISS:缓存未命中,请求已转发给后端,且响应已被缓存(除非被Cache-Control: no-store拦截) -
BYPASS:因proxy_cache_bypass条件满足,跳过缓存直接打后端,但响应仍可能被缓存 -
EXPIRED:缓存存在但已过期,Nginx 异步更新(需开启proxy_cache_use_stale updating) -
STALE:返回的是过期缓存,同时后台正在更新
注意:$upstream_cache_status 不会显示 UPDATING,它只反映本次响应的来源状态;若需区分“正在更新中”,得结合 $upstream_http_x_cache_status(需后端主动设置)或自定义逻辑。
立即学习“前端免费学习笔记(深入)”;
容易漏掉的兼容性细节
这个 header 对前端调试有用,但默认不会出现在 CORS 响应头里。如果前端跨域请求,必须显式放行:
- 加
add_header Access-Control-Expose-Headers "X-Cache-Status"; - 该指令需放在与
add_header X-Cache-Status相同的 location 块,且位置要靠前(否则可能被后续配置覆盖) - 若启用 gzip,
add_header注入的 header 仍有效;但若用了sub_filter修改响应体,header 注入顺序不受影响 - 测试时用
curl -I最直接,浏览器开发者工具的 Network 面板需点开 Response Headers 才能看到(部分浏览器默认折叠自定义 header)
变量生效依赖完整的代理链路,如果中间有其他反向代理(比如 Cloudflare),$upstream_cache_status 只反映 Nginx 本机缓存行为,跟上游无关。


















