nginx 缓存与 cors 共用时需禁用后端 cors 头缓存并强制添加统一头:用 proxy_ignore_headers 忽略后端 cors 头,add_header ... always 统一注入,proxy_hide_header 配合防止透传,options 响应须禁用缓存。

缓存和 CORS 一起用时容易出错,核心问题在于:Nginx 的 add_header 会对缓存响应也生效,如果后端已返回了 Access-Control-Allow-Origin,Nginx 又叠加一次,浏览器就会收到重复值,直接报错。
避免缓存中混入旧 CORS 头
启用 proxy_cache 时,必须禁用后端自带的 CORS 响应头被缓存——否则下次返回缓存内容时,它会带着旧的 Origin 值,再被 add_header 补一个新值,造成冲突。
- 在 location 或 upstream 块中加:
proxy_ignore_headers Access-Control-Allow-Origin Access-Control-Allow-Credentials Access-Control-Allow-Methods; - 这条指令让 Nginx 忽略后端返回的这些 CORS 头,只信任你自己通过
add_header设置的版本 - 特别注意:若后端是 Node.js、Spring Boot 等框架且已开启全局 CORS,这一步必不可少
确保 add_header 在缓存和非缓存路径下行为一致
add_header 默认不作用于缓存响应中的错误码(如 304、404),但 CORS 头需要始终存在。解决方法是加上 always 参数:
add_header 'Access-Control-Allow-Origin' 'https://myapp.com' always;add_header 'Access-Control-Allow-Credentials' 'true' always;- 加了
always后,哪怕返回的是缓存命中(304)或静态文件(200),CORS 头也不会丢失
防止 proxy_hide_header 和缓存逻辑打架
如果你用 proxy_hide_header 移除后端 CORS 头,它本身不干预缓存逻辑;但若缓存未刷新,旧响应仍可能含被隐藏过的头——所以要配合 proxy_ignore_headers 使用,而不是只靠 hide。
- 推荐组合写法:
proxy_hide_header Access-Control-Allow-Origin;+proxy_ignore_headers Access-Control-Allow-Origin; - 前者防止当前请求透传后端头,后者防止该头被存进缓存
- 二者缺一不可,尤其在灰度发布或后端频繁更新 CORS 配置时
OPTIONS 预检请求别被缓存干扰
浏览器对 OPTIONS 请求的预检结果会按 Access-Control-Max-Age 缓存。但如果 Nginx 把 OPTIONS 响应也缓存了,可能导致后续实际请求拿到过期的预检策略。
- 在处理 OPTIONS 的 location 或 if 块里,显式关闭缓存:
add_header 'Cache-Control' 'no-cache, no-store, must-revalidate' always; - 或者更彻底:用
expires -1;和add_header Pragma 'no-cache'; - 确保预检响应不会进入
proxy_cache,避免策略“冻住”











