proxy_no_cache无法直接基于响应状态码(如500、401)判断,需通过后端添加X-Sensitive-Log头或URI路径匹配等前置信号,结合proxy_cache_bypass与proxy_no_cache协同实现敏感响应不缓存。

proxy_no_cache 本身不支持直接基于响应状态码(如 500、401)做判断,因为它是请求阶段解析的指令,而状态码在响应返回后才可知。但你可以通过 间接方式实现“敏感日志响应不进缓存”,核心思路是:让带敏感日志特征的响应,在发出前就被标记为不可缓存。
关键在于——把状态码相关的决策前置到请求阶段可识别的信号上,再结合后端配合或 header 注入。
✅ 基于后端主动标记敏感响应(推荐)
让后端在返回敏感日志类响应时,统一添加一个自定义响应头,例如:
X-Sensitive-Log: true
Nginx 可据此在响应阶段阻止缓存写入:
map $upstream_http_x_sensitive_log $no_cache_by_log {
"true" 1;
default 0;
}
location /api/ {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_bypass $no_cache_by_log;
proxy_no_cache $no_cache_by_log;
# 其他缓存控制保持不变
proxy_cache_valid 200 302 10m;
proxy_cache_key "$host$request_uri";
}
⚠️ 注意:
$upstream_http_x_sensitive_log是 Nginx 自动将上游响应头X-Sensitive-Log映射成的变量(命名规则:$upstream_http_+ 小写+下划线替换-)。只要后端返回该 header,Nginx 就能捕获并触发绕过。
✅ 基于错误页面路径或 location 分离敏感接口
如果敏感日志只出现在特定路径(如 /debug/log、/admin/dump),直接用 URI 判断更稳定:
map $request_uri $no_cache_by_debug_path {
~*^/(debug|admin)/log 1;
~*^/api/v1/trace 1;
default 0;
}
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_bypass $no_cache_by_debug_path;
proxy_no_cache $no_cache_by_debug_path;
}
这种方式无需后端改造,适合快速隔离调试类接口。
❌ 不可行的方式(常见误区)
- 直接写
proxy_no_cache $status;→ 语法错误,$status在proxy_no_cache上下文中不可用; - 试图用
if ($status = 500) { ... }包裹proxy_no_cache→ Nginx 不允许在if中使用代理缓存指令; - 依赖
Cache-Control: no-cache响应头 → 它只影响客户端,不影响 Nginx 代理缓存行为;Nginx 默认仍会存储并复用该响应,除非你显式配置proxy_no_cache。
✅ 补充建议:避免日志污染缓存的组合策略
- 后端返回敏感日志时,同时设置
Cache-Control: private, no-store,作为客户端和中间层的双重提示; - 对所有
X-Sensitive-Log: true响应,额外加一条日志记录,便于审计:log_format cache_skip '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' 'cache:"$upstream_cache_status" skip_reason:"log"'; access_log /var/log/nginx/skip.log cache_skip if=$no_cache_by_log; - 静态资源、健康检查(如
/healthz)、公开文档等路径,单独配 location 并关闭相关 map 判断,防止误判。
不复杂但容易忽略。真正起效的是“请求可识别信号 + proxy_cache_bypass + proxy_no_cache 成对启用”,而不是等状态码出来再动作。











