301永久重定向应设长缓存(如7d),因语义承诺长期有效;302临时重定向需设短缓存(如2m),避免掩盖上游状态变化;二者必须分开配置proxy_cache_valid,不可合并进any规则,否则导致缓存策略失效。

proxy_cache_valid 301 和 302 的缓存行为差异
301(永久重定向)和 302(临时重定向)在语义上不同,但 Nginx 默认不区分它们的缓存策略——除非你显式用 proxy_cache_valid 单独配置。如果你只写 proxy_cache_valid 200 302 1h;,那 301 就不会被覆盖,可能走默认或 fallback 规则(比如 proxy_cache_valid any 1m;),导致 301 被缓存过短甚至不缓存。
常见错误现象是:用户访问旧 URL 后跳转到新地址,但过几分钟再试又触发一次后端重定向逻辑(比如 PHP 或 Node.js 动态生成 301),说明 301 没被有效缓存;而 302 缓存太久又会导致用户无法及时感知目标变更。
- 301 适合设长些(如
1d或7d),因语义上“永久”,且浏览器/CDN 也倾向长期信任 - 302 建议设短(如
30s~5m),避免掩盖上游服务的临时状态变化 - 必须把
301和302分开写,不能合并进同一行带any的规则里,否则会被后者覆盖
如何在 location 中正确配置 301/302 独立缓存时间
直接在需要缓存重定向的 location 块内写两条独立的 proxy_cache_valid 指令即可,顺序无关,Nginx 会按状态码精确匹配:
location /old-path/ {
proxy_pass http://backend;
proxy_cache my_cache_zone;
proxy_cache_valid 301 7d;
proxy_cache_valid 302 2m;
proxy_cache_valid 200 10m;
}
注意点:
-
proxy_cache_valid必须出现在启用proxy_cache的上下文中,否则无效 - 不要漏掉
proxy_cache_key—— 如果重定向依赖请求参数(如?ref=abc),需确保$args在 key 中,否则不同参数的 302 可能命中同一缓存项 - 若上游返回的是带
Cache-Control: no-cache的 302,还需加proxy_ignore_headers Cache-Control;才能让proxy_cache_valid生效
为什么 301/302 缓存经常“不生效”
最常踩的坑不是配置错,而是没意识到缓存是否真正写入或被复用:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 响应头含
Set-Cookie:Nginx 默认不缓存带该头的响应,哪怕状态码是 301 —— 加proxy_ignore_headers Set-Cookie;可绕过(仅当你确认 cookie 不影响重定向逻辑时) - 后端返回了
Vary头(如Vary: User-Agent):Nginx 会为每个不同值生成独立缓存 key,容易造成缓存碎片,建议上游去掉不必要的Vary - 测试时用
curl -I看不到X-Cache: HIT?检查是否启用了proxy_cache_lock on;,首次未命中时会阻塞后续相同请求,导致你以为“没缓存”,其实只是还没写完 - 日志中
$upstream_cache_status显示MISS或BYPASS:前者说明 key 不匹配或 inactive 过期;后者说明被proxy_no_cache或条件指令跳过
与 CDN 缓存的协作关系
proxy_cache_valid 对 301/302 的设置,只影响 Nginx 自身缓存行为,不影响 CDN 边缘节点。如果你用 Cloudflare 或阿里云全站加速,它们看到的仍是原始响应头。
要让 CDN 也缓存重定向,必须额外加响应头:
add_header Cache-Control "public, max-age=86400"; # 让 CDN 缓存 301 一天 add_header Cache-Control "public, max-age=120"; # 让 CDN 缓存 302 两分钟
关键点:
- 这两条
add_header需放在同一location内,且在proxy_pass之后才生效(Nginx 是流式处理,header 要在响应生成前注入) - 不能只靠
proxy_cache_valid期待 CDN “自动同步”缓存时长 —— 它们完全不读这个指令 - 如果上游已返回
Cache-Control,而你又用add_header覆盖,要注意 Nginx 默认会保留上游头;需配合proxy_hide_header Cache-Control;防止冲突
真正起作用的是响应头本身,不是 Nginx 内部的缓存计时器。很多人调了半天 proxy_cache_valid 却发现 CDN 还是不缓存,问题就出在这里。










