Nginx子域名跨域问题排查:Node.js API跨域访问异常
核心问题:Nginx与Node.js CORS配置冲突
从响应头能明显看到,www.example.com访问时返回了两个Access-Control-Allow-Origin头(*和https://www.example.com),这是浏览器CORS规则严格禁止的,直接导致请求失败。
对疑问的逐一解答
第一个if语句是否存在问题?
你Nginx里的正则https?://.*\.example\.com(:[0-9]+)?是正确的——它能匹配example.com本身、www.example.com、sub2.example.com等所有二级/顶级关联域名(含端口)。问题不在这个正则上。Access-Control-Allow-Origin: *是否允许所有域名访问?
是的,但有个关键限制:当设置*时,不能同时设置Access-Control-Allow-Credentials: true,浏览器会直接拒绝这种组合的响应。而example.com访问成功,是因为当时只有Node.js返回的*头,没有Nginx添加的Credentials头,所以浏览器接受了。Node.js的cors中间件是否有影响?
影响极大。默认的app.use(cors())会自动给所有请求添加Access-Control-Allow-Origin: *头,而你的Nginx又在匹配到合法Origin时添加了另一个Access-Control-Allow-Origin: $http_origin和Credentials: true头,两者叠加导致响应头重复,触发浏览器CORS错误。至于预请求OPTIONS正常,是因为Nginx里对OPTIONS请求直接
return 204,没有转发到Node.js,所以Node的cors中间件没生效,只有Nginx的CORS配置生效,没有冲突。
解决方案(二选一)
方案1:关闭Node.js的cors中间件,完全用Nginx处理CORS
删掉Node代码里的app.use(cors()),保留Nginx现有配置即可。这样所有请求的CORS头都由Nginx统一控制,不会出现重复。
方案2:关闭Nginx的CORS配置,用Node.js的cors中间件精确控制
- 删掉Nginx中所有和CORS相关的
if判断、add_header、set $cors代码块。 - 修改Node.js的cors配置,指定允许的域名:
这种方式更灵活,适合需要在Node层动态控制CORS规则的场景。const cors = require('cors'); const app = express(); // 允许所有example.com相关域名 const corsOptions = { origin: /https?:\/\/.*\.example\.com(:[0-9]+)?/, credentials: true }; app.use(cors(corsOptions));
内容的提问来源于stack exchange,提问作者oderfla

