proxy_cache_valid 对 301 状态码生效,仅作用于 Nginx 本机缓存层;需配合 add_header Cache-Control 显式设置才能让 CDN 和浏览器识别长效缓存意图。

proxy_cache_valid 对 301 状态码是否生效?
生效,但仅限于 Nginx 本机缓存层 —— 它不会让 CDN 或浏览器多缓存一秒。301 响应本身可被 proxy_cache 缓存,proxy_cache_valid 301 1h 表示 Nginx 收到上游返回的 301 后,会在本地缓存 1 小时;下次相同请求进来,Nginx 直接复用这个 301 响应,不再回源。
常见错误现象:加了 proxy_cache_valid 301 1d,但浏览器或 CDN 仍频繁回源。这是因为:
- CDN 只看响应头里的
Cache-Control或Expires,而proxy_cache_valid不自动添加这些头 - 浏览器对 301 默认强缓存(除非显式禁用),但若后端没发
Cache-Control,某些 CDN 会按自身策略降级处理(如只缓存 5 分钟)
如何让 301 同时在 Nginx 和 CDN 层都长效缓存?
必须两步走:先让 Nginx 缓存 301,再主动注入缓存头给下游。否则只做一半,CDN 无法识别你的“想缓存 1 天”的意图。
实操建议:
- 在
location块中启用缓存并设置状态码规则:proxy_cache_valid 301 1d; - 用
add_header Cache-Control "public, max-age=86400";显式声明,覆盖后端可能返回的no-cache或空头 - 如果后端返回了
Cache-Control: no-store,需配合proxy_ignore_headers Cache-Control;才能生效 - 避免对含 Cookie 或认证头的请求缓存 301,否则可能把用户专属重定向错发给其他人 —— 可加
proxy_cache_key "$scheme$request_method$host$uri$is_args$args";排除 $cookie_ 类变量
为什么 301 缓存周期常比 200 更长?
301 是永久重定向,语义上代表资源已**稳定迁移**,不像 200 内容可能随时更新。所以生产环境常设为 1 天甚至 30 天,降低回源压力。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
但要注意几个边界条件:
-
proxy_cache_valid 301 30d≠ 浏览器永远不重验证:若用户手动刷新(F5),部分浏览器会带Cache-Control: max-age=0,触发强制校验(这时 Nginx 若未配置proxy_cache_use_stale updating,就会阻塞等待新响应) - 如果上游服务偶尔返回 302(临时重定向)混在 301 流量里,要单独配
proxy_cache_valid 302 5m,否则会被 301 规则覆盖,导致临时跳转也被缓存过久 - 使用
inactive=1d配合proxy_cache_path时,即使设置了 30d,若该 301 在 1 天内没人访问,也会被清理 —— 这个时间由inactive控制,和proxy_cache_valid无关
调试 301 缓存是否命中?
最直接的方式是看响应头中的 X-Cache 标记,它依赖 add_header X-Cache "$upstream_cache_status";。
典型输出含义:
-
X-Cache: HIT:Nginx 从本地缓存直接返回了 301 -
X-Cache: MISS:Nginx 没有缓存,回源拿到 301 并写入缓存(首次或过期后) -
X-Cache: EXPIRED:缓存存在但已超proxy_cache_valid设定时间,Nginx 回源并尝试异步更新(需开启proxy_cache_use_stale updating)
容易被忽略的是:$upstream_cache_status 只反映 Nginx 本机缓存行为,它完全不体现 CDN 是否命中 —— 那得去 CDN 后台查日志或看其返回的 X-Cache(如有)。

















