nginx需显式处理options预检请求并统一配置带always标志的cors头,确保access-control-allow-headers精确列出authorization等自定义头,且access-control-allow-origin不能为*(若withcredentials为true)。

要让前端用 Axios 发送带自定义鉴权头(比如 Authorization: Bearer xxx 或 X-Api-Key)的跨域请求成功,Nginx 必须同时满足两个关键条件:正确响应预检(OPTIONS)请求,并在实际请求中返回合法的 CORS 头。单纯加几个 add_header 是不够的,尤其当请求含非简单头时,浏览器一定会先发 OPTIONS,而 Nginx 若未专门处理它,就会直接 405 或丢掉 CORS 头,导致跨域失败。
必须显式处理 OPTIONS 预检请求
带自定义头的请求属于“复杂请求”,浏览器强制发起 OPTIONS 预检。Nginx 默认不代理 OPTIONS 到后端,也不自动返回 CORS 头——你得手动拦截并快速响应:
- 用
if ($request_method = 'OPTIONS')拦截,不要依赖后端处理 - 返回
204 No Content,避免响应体干扰 - 在该分支里补全所有必要 CORS 头,尤其是
Access-Control-Allow-Headers要明确列出你的自定义头名(如Authorization,X-Api-Key)
Access-Control-Allow-Headers 必须精确匹配前端所发的头
Axios 请求若设置了 headers: { Authorization: 'Bearer abc123' },Nginx 的 Access-Control-Allow-Headers 就不能只写 *(部分浏览器不认),也不能漏掉 Authorization:
- 推荐写法:
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,X-Api-Key' always; - 注意大小写不敏感,但拼写必须一致;多个头用英文逗号+空格分隔
- 如果用了
withCredentials: true,Access-Control-Allow-Origin不能为*,需指定具体域名(如https://your-app.com)
确保所有 CORS 头在 OPTIONS 和真实请求中都生效
Nginx 的 add_header 默认不作用于 204/304 等无响应体状态码,所以必须加 always 标志:
add_header 'Access-Control-Allow-Origin' 'https://your-app.com' always;add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;add_header 'Access-Control-Allow-Credentials' 'true' always;add_header 'Access-Control-Max-Age' '86400' always;
附:一个可直接复用的 location 示例
假设你代理 /api/ 到后端,且前端带 Authorization 和 X-Trace-ID 头:
location /api/ {
# 预检请求处理
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://your-app.com' 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,If-Modified-Since,Cache-Control,Content-Type,Authorization,X-Trace-ID' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Max-Age' '86400' always;
add_header 'Content-Length' 0 always;
add_header 'Content-Type' 'text/plain charset=utf-8' always;
return 204;
}
<pre class="brush:php;toolbar:false;"># 实际请求
proxy_pass http://backend:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 所有响应都带 CORS 头(含 204)
add_header 'Access-Control-Allow-Origin' 'https://your-app.com' 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,If-Modified-Since,Cache-Control,Content-Type,Authorization,X-Trace-ID' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Max-Age' '86400' always;}
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











