解决Nginx跨域问题需理解CORS预检机制,核心是动态匹配Origin、精准设置Allow-Credentials/Methods/Headers,并拦截OPTIONS返回204及完整CORS头,缺一不可。

解决Nginx跨域问题,核心不是加一堆add_header,而是理解浏览器CORS预检机制与Nginx响应头的协同逻辑。真正稳定的配置,必须同时满足:允许指定源、携带凭证可选、预检缓存合理、方法与头白名单精准——缺一不可。
基础CORS响应头:必须显式声明的三项
仅设置Access-Control-Allow-Origin远远不够。浏览器发起带凭证(如cookie、Authorization)的请求时,若该头值为*,会直接拒绝。因此:
- Origin必须明确指定,不能用通配符(除非确认不带凭证);生产环境建议通过变量动态匹配可信域名
- Access-Control-Allow-Credentials: true需与Origin严格对应,二者必须共存或共弃
-
Access-Control-Allow-Methods和Access-Control-Allow-Headers要精确列出前端实际用到的方法和自定义头(如
X-Requested-With、Content-Type),避免过度开放
预检请求(OPTIONS)的正确拦截与响应
非简单请求(如PUT、DELETE、含自定义Header)会先发OPTIONS预检。Nginx必须拦截并返回204(无内容),且响应头中必须包含上述CORS头——否则预检失败,后续请求根本不会发出。
- 用
location = /或location ^~ /api/等匹配路径,在内部if ($request_method = 'OPTIONS')判断 - 匹配后立即
add_header全部CORS头,并return 204,不代理、不重写、不走后端 - 注意:
if在location内可用,但在server级别慎用;避免嵌套if或复杂条件
生产可用的最小化模板(支持带凭证+动态Origin)
以下配置适用于Vue/React前端部署在https://fe.example.com,后端API在https://api.example.com,且需传递session cookie的典型场景:
# 在 server 或 location 块内
set $cors_origin "";
<p>if ($http_origin ~* "^https?://(fe.example.com|localhost:8080)$") {
set $cors_origin $http_origin;
}</p><p>if ($cors_origin != "") {
add_header 'Access-Control-Allow-Origin' "$cors_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Accept,Authorization' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
}</p><h1>处理预检请求</h1><p>if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 17280000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}</p>说明:使用always参数确保即使后端返回302/401等状态码,CORS头仍生效;Access-Control-Expose-Headers用于让JS读取响应中的自定义字段(如分页总条数)。
调试与验证关键点
配置后别急着刷新页面,先用curl或浏览器Network面板验证:
- 对任意API接口发一个带
Origin和Authorization头的OPTIONS请求,检查响应是否有204 + 所有CORS头 - 再发真实请求(如POST),查看Response Headers是否含
Access-Control-Allow-Origin和Access-Control-Allow-Credentials - 如果控制台报错“Credentials flag is true…”,大概率是Origin值为
*或缺失Allow-Credentials头 - Nginx日志中开启
debug级别可追踪header添加过程(临时启用,避免线上长期开启)










