add_header的always参数确保CORS响应头在所有HTTP状态码(包括4xx/5xx)中强制输出,避免因错误响应缺失跨域头导致浏览器拦截真实错误信息;必须为每一行add_header显式添加always,不可继承或省略。

默认情况下,add_header 只在 2xx 和 3xx 响应中生效,4xx/5xx 错误响应不会携带你设置的 CORS 头——这会导致前端收到 401、404、500 等错误时,浏览器因缺失 Access-Control-Allow-Origin 等头而报“跨域被拒绝”,实际错误信息反而被拦截,调试困难。解决的关键就是加 always 参数。
必须为每个 add_header 显式加上 always
always 不是全局开关,也不能继承。只要你想让某个响应头出现在所有状态码(包括 400、404、500、502 等)中,就必须在每一行 add_header 后面都写上 always。
- ✅ 正确:
add_header Access-Control-Allow-Origin "*" always; - ✅ 正确:
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; - ❌ 错误:
add_header Access-Control-Allow-Origin "*";(缺 always,4xx/5xx 不生效) - ❌ 错误:
add_header Access-Control-Allow-Origin "*" always; add_header Access-Control-Allow-Headers "Content-Type";(第二行没加 always,依然不生效)
配合预检请求(OPTIONS)一起配置
跨域请求常先发一个 OPTIONS 预检,它本身也可能是失败的(比如后端未处理 OPTIONS)。确保预检响应也带全 CORS 头,并统一用 always:
- 在
if ($request_method = 'OPTIONS')块内,return 204前的所有add_header也要加always - 例如:
add_header Access-Control-Max-Age "1728000" always; - 避免只在
if块外加always,而块内漏掉——预检失败时照样没头
验证是否生效的简单方法
不用等真实错误,可手动触发一个 4xx 响应来测试:
- 在 location 中临时加一行:
return 404 "Not found"; - 同时确保该 location 有带
always的 CORS 头,例如:add_header Access-Control-Allow-Origin "*" always; - 用 curl 测试:
curl -i -H "Origin: https://example.com" http://your-nginx/api/test - 检查响应中是否包含
Access-Control-Allow-Origin: *,且状态码是404
注意和 proxy_set_header 的区别
add_header ... always 是加给浏览器看的响应头,用于跨域校验;proxy_set_header 是加给后端服务的请求头,对浏览器完全不可见。两者作用对象不同,不能互相替代。
- 跨域失败?检查是不是误用了
proxy_set_header来设Access-Control-Allow-Origin - 后端返回了 502,但浏览器报 CORS 错误?大概率是 Nginx 的
add_header缺always,导致 502 响应没带跨域头











