Nginx 默认不信任后端响应头(如Cache-Control、Set-Cookie、Expires)的缓存指令,而是优先采用proxy_cache_valid配置;需显式设置proxy_ignore_headers等指令才能让其尊重或忽略特定头,否则可能缓存失效或误缓存。

Nginx 作为 HTTP 反向代理时,后端响应头(如 Cache-Control、Expires、Set-Cookie)会直接影响缓存行为。但默认情况下,Nginx 不会无条件信任或继承这些头,而是按自身规则决定是否缓存、缓存多久、是否忽略某些头。关键在于理解 Nginx 如何“处理”而非“转发”这些响应头。
后端响应头对 Nginx 缓存的实际影响
Nginx 的 proxy_cache 模块在接收后端响应后,会做两件事:
- 判断该响应是否允许被缓存(基于状态码、方法、响应头等);
- 决定缓存有效期(优先级:
proxy_cache_valid> 后端Cache-Control/Expires,除非显式启用proxy_cache_use_stale或proxy_ignore_headers)。
后端返回的 Cache-Control: no-cache 或 max-age=60,默认不会覆盖你配置的 proxy_cache_valid,除非你主动让 Nginx 尊重它。
关键响应头的处理逻辑与配置建议
-
Cache-Control和Expires
默认会被 Nginx 忽略用于缓存决策——也就是说,即使后端返回Cache-Control: max-age=5,只要你在proxy_cache_valid 200 10m;中写了 10 分钟,就以 10 分钟为准。
若想让 Nginx 尊重后端的缓存指令,需显式关闭忽略:proxy_ignore_headers Cache-Control Expires;
⚠️ 注意:一旦放开,就要确保后端返回的
Cache-Control是可信且符合业务预期的(例如不返回private或no-store给公共接口)。 -
Set-Cookie
只要响应里含Set-Cookie头,Nginx 默认拒绝缓存该响应(哪怕状态码是 200),因为带 Cookie 通常意味着响应是用户私有内容。
如果后端误加了Set-Cookie(比如日志埋点 cookie),又希望缓存,可强制忽略:proxy_ignore_headers Set-Cookie; proxy_hide_header Set-Cookie;
这样既不让客户端收到该头,也避免因它的存在导致缓存跳过。
-
Vary头
Nginx 默认不解析Vary,也不会自动将其纳入缓存键。若后端依赖Vary: Accept-Encoding, User-Agent,你需要手动扩展proxy_cache_key:proxy_cache_key "$scheme$host$request_uri$is_args$args$http_accept_encoding$http_user_agent";
否则不同
Accept-Encoding的请求可能命中错误缓存(比如 gzip 响应被返回给不支持 gzip 的客户端)。
实用配置组合示例
location /api/v1/ {
proxy_pass https://backend.example.com;
# 启用缓存区
proxy_cache api_cache;
# 显式控制哪些状态码缓存多久(优先级最高)
proxy_cache_valid 200 302 5m;
proxy_cache_valid 404 1m;
# 允许忽略后端干扰头
proxy_ignore_headers Set-Cookie Cache-Control Expires;
proxy_hide_header Set-Cookie;
# 自定义缓存键,排除时间戳类参数
proxy_cache_key "$scheme$host$request_uri$is_args$arg_id$arg_type";
# 允许在后端异常时返回旧缓存
proxy_cache_use_stale error timeout http_500;
# 添加调试头
add_header X-Cache-Status $upstream_cache_status;
}这种写法下,后端即使返回 Cache-Control: no-cache 或 Set-Cookie: session=xxx,Nginx 仍会缓存,并按你设定的 5m 生效,同时不把 Set-Cookie 透传给客户端。
验证是否生效
检查响应头中的 X-Cache-Status:
-
HIT:缓存命中,说明 Nginx 成功忽略了后端的禁止缓存头; -
MISS:首次请求或缓存未生成; -
STALE:用了过期缓存(比如后端挂了,但proxy_cache_use_stale生效)。
只要看到 HIT,就证明你对响应头的处理逻辑已起效。
不复杂但容易忽略


















