Nginx缓存需手动创建cache目录并赋权;proxy_cache_valid须显式配置304;proxy_buffering、proxy_cache_use_stale、proxy_cache_lock缺一不可;proxy_ignore_headers慎用,含Set-Cookie响应默认不缓存。

缓存路径和 keys_zone 必须手动创建并赋权
直接写 proxy_cache_path /var/cache/nginx ... 不会自动建目录,Nginx 启动时会静默失败(nginx -t 也不报错),但日志里会出现 open() "/var/cache/nginx/..." failed (2: No such file or directory)。
必须提前执行:
sudo mkdir -p /var/cache/nginx sudo chown nginx:nginx /var/cache/nginx sudo chmod 755 /var/cache/nginx
注意:nginx 用户名可能因发行版而异(如 www-data 在 Debian/Ubuntu),需确认 ps aux | grep nginx 或查 nginx.conf 中的 user 指令。
proxy_cache_valid 对 200 和 304 响应要分开控制
后端返回 304 Not Modified 是协商缓存成功的结果,但默认情况下它不会被 proxy_cache_valid 200 10m 覆盖——Nginx 只按响应状态码匹配规则,304 必须显式声明,否则不进缓存。
常见错误配置:
proxy_cache_valid 200 10m; # ← 304 被忽略,每次仍要问后端
正确做法是补上:
proxy_cache_valid 200 301 302 10m;-
proxy_cache_valid 304 1h;(或更长,因为 304 本身不带 body,开销极小) - 如果后端支持 ETag + If-None-Match,务必保留
proxy_set_header If-None-Match $http_if_none_match;,否则协商失效
location 块里漏掉 proxy_buffering 或 proxy_cache_use_stale 就等于没缓存
缓存生效 ≠ 请求一定走缓存。比如后端超时、502、503 时,默认直接透传错误给客户端——用户看到的是错误页,而不是“上一次还能用的缓存”。
关键配置缺一不可:
-
proxy_buffering on;:关闭会导致流式响应无法缓存(尤其 JSON API) -
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;:让出错时仍可返回旧缓存 -
proxy_cache_lock on;:防止缓存未命中时多个并发请求同时打到后端(即“缓存雪崩”) -
add_header X-Cache-Status $upstream_cache_status;:调试时看是HIT、MISS还是STALE
静态资源缓存别只靠 Nginx,得和后端 HTTP 头协同
Nginx 的 proxy_cache_valid 是兜底策略,但优先级低于后端返回的 Cache-Control 和 Expires。如果后端 PHP/Node.js 返回了 Cache-Control: no-cache,Nginx 默认会尊重它,导致缓存完全不生效。
解决办法只有两个:
- 后端代码改头:比如 Laravel 用
response()->cache(...),Express 用res.set('Cache-Control', 'public, max-age=3600') - 在 Nginx 里强制覆盖:
proxy_ignore_headers Cache-Control Expires Set-Cookie;(慎用,Set-Cookie忽略会导致登录态混乱)
特别注意:含 Set-Cookie 的响应默认不缓存,即使你写了 proxy_cache_valid 200 1h——这是 Nginx 硬性限制,不是 bug。


















