Nginx可通过proxy_no_cache配合map指令动态响应上游X-No-Cache头实现条件不缓存:先用map将$upstream_http_x_no_cache映射为$no_cache_flag,再在location中设proxy_no_cache $no_cache_flag。

要让 Nginx 缓存系统在收到上游(如后端应用)返回的特定自定义 Header(例如 X-No-Cache: true)时,自动跳过缓存,关键不是靠 add_header,而是使用 proxy_no_cache 或 fastcgi_no_cache 指令配合变量判断——它能动态响应上游响应头内容,实现“条件式不缓存”。
核心原理:用 proxy_no_cache 响应上游 Header 决策缓存行为
Nginx 的缓存模块(proxy_cache)本身不解析响应体或自定义 Header,但支持通过 proxy_no_cache 指令,根据变量值决定是否跳过缓存写入。该变量可来自:
– 上游响应头(需先用 proxy_pass_request_headers off 不是必须,但需确保 header 被读取);
– 更可靠的是用 map 指令将上游响应头映射为布尔变量。
注意:proxy_no_cache 作用于**响应阶段**,仅影响当前请求是否写入缓存(即不存),不影响是否从缓存读取(那是 proxy_cache_bypass 的事)。
配置步骤(以 X-No-Cache: true 为例)
以下配置适用于反向代理场景(PHP-FPM 同理,替换为 fastcgi_no_cache 和 fastcgi_cache):
-
第一步:在 http 块顶部定义 map,提取并转换上游响应头
```nginx
map $upstream_http_x_no_cache $no_cache_flag {
default 0;
~*true 1;
~*yes 1;
~*on 1;
}```
说明:$upstream_http_x_no_cache是 Nginx 自动暴露的变量,值为上游返回的X-No-Cache响应头内容;map将其转为 0/1 整数,便于后续逻辑判断。 -
第二步:在 server 或 location 块中启用缓存,并绑定 no_cache 条件
```nginx
location / {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_use_stale error timeout updating;
proxy_no_cache $no_cache_flag;
# 可选:同时绕过读取缓存(即强制回源)
# proxy_cache_bypass $no_cache_flag;
}```proxy_no_cache $no_cache_flag表示:只要变量值非 0(即上游返回了 true/yes/on),本次响应就不写入缓存。 -
第三步:确保上游确实返回了该 Header
例如 PHP 中:header('X-No-Cache: true');
Node.js Express:res.set('X-No-Cache', 'true');
Spring Boot:response.setHeader("X-No-Cache", "true");
注意大小写:Nginx 中$upstream_http_x_no_cache对应首字母小写、连字符转下划线的格式(X-No-Cache → x_no_cache)。
常见问题与避坑点
-
Header 没被识别?检查 upstream 是否真的返回了该 Header(用 curl -v 或浏览器 Network 验证);确认 Nginx 版本 ≥ 1.7.5(
map支持响应头变量);确认未启用underscores_in_headers on干扰解析(默认 off,建议保持)。 -
缓存仍被写入?确认
proxy_no_cache写在启用了proxy_cache的 location 块内;变量名拼写一致($no_cache_flag);避免在 if 块中使用proxy_no_cache(不生效)。 -
想同时禁止读和写缓存?加一行
proxy_cache_bypass $no_cache_flag;,这样当上游返回 true 时,既不读缓存也不写缓存,100% 回源。
补充:FastCGI 场景(PHP-FPM)等效写法
只需替换指令前缀:
– map $upstream_http_x_no_cache $no_cache_flag { ... } 不变;
– location 中改用:
```nginx
fastcgi_cache my_php_cache;
fastcgi_cache_valid 200 302 5m;
fastcgi_no_cache $no_cache_flag;
fastcgi_cache_bypass $no_cache_flag;
```


















