直接加 always 参数就能解决。nginx 的 add_header 默认只在 2xx 和部分 3xx(如 301、304)响应中生效,遇到 404、500、401、302 等状态码时,你配的 access-control-allow-origin 等头根本不会发出去——浏览器收不到,就直接拦截响应,前端连错误内容都拿不到。

直接加 always 参数就能解决。Nginx 的 add_header 默认只在 2xx 和部分 3xx(如 301、304)响应中生效,遇到 404、500、401、302 等状态码时,你配的 Access-Control-Allow-Origin 等头根本不会发出去——浏览器收不到,就直接拦截响应,前端连错误内容都拿不到。
必须每行都加 always,不能省略
always 不是全局开关,也不会继承。只要希望某个响应头出现在所有状态码下,就必须在每一行 add_header 后面明确写上:
add_header Access-Control-Allow-Origin "*" always;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;add_header Access-Control-Expose-Headers "Content-Length, X-RateLimit-Remaining" always;
特别注意 error_page 和自定义错误页
如果你用了 error_page 404 /404.html; 这类配置,Nginx 会跳转到新的 location 处理,而原 server 或上级 location 中的 add_header 不会自动带过去。必须单独为错误页 location 补上带 always 的头:
error_page 404 /404.html;location = /404.html {root /usr/share/nginx/html;add_header Access-Control-Allow-Origin "*" always;add_header Access-Control-Allow-Methods "GET" always;}
OPTIONS 预检请求也要覆盖
预检请求本身可能返回 204、405 或 500,同样需要 always。不能只靠外层配置,得在 if ($request_method = 'OPTIONS') 块里显式加:
if ($request_method = 'OPTIONS') {add_header Access-Control-Allow-Origin "*" always;add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,Content-Type,Authorization" always;add_header Access-Control-Max-Age "1728000" always;return 204;}
验证是否真生效
别等线上出问题才查。用 curl 快速验证:
- 触发 404:
curl -I -H "Origin: https://example.com" https://your.site/nonexist→ 检查响应头是否有Access-Control-Allow-Origin且状态码是 404 - 触发 500:
curl -I -X POST https://your.site/api/crash(假设后端会崩)→ 同样看头是否出现 - 浏览器 Network 面板里找任意失败请求,点开 Response Headers,确认关键 CORS 头都在











