前后端分离生产环境下跨域AJAX请求被浏览器拦截求助
跨域请求拦截问题排查与解决
环境与架构说明
- 前端:原生PHP搭建的Web应用服务器,地址
http://192.168.1.200:3000(非HTTPS) - 后端:Node.js+Express.js API服务器,通过Nginx反向代理对外提供服务,域名
https://apihost.mycompany.com,测试端点https://apihost.mycompany.com/auth/info - 问题现象:开发阶段同机器测试正常,生产环境下AJAX请求被浏览器拦截,请求未到达API服务器,仅浏览器开发者工具提示跨域错误,无其他控制台报错
相关代码
前端PHP页面中的jQuery AJAX请求
function getUserInfo(){ $.ajax({ type: "GET", url: `https://apihost.mycompany.com/auth/info`, xhrFields: { withCredentials: true }, dataType: "json", success: function(response) { // 页面展示逻辑 }, error: function(response){ // 错误提示逻辑 }, }); }
Express服务器CORS配置
const whiteListOrigin = ['https://livefrontend.server.com','http://192.168.1.200:3000']; const whiteListReqMethods = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']; var corsOptions = { origin: function (origin, callback) { if (whiteListOrigin.indexOf(origin) !== -1) { callback(null, true) } else { callback(new Error('Not allowed by CORS')) } }, methods: whiteListReqMethods, allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'], credentials: true, maxAge: 600, exposedHeaders: ['*', 'Authorization' ], preflightContinue: true, optionsSuccessStatus: 204 }; app.options("*", function(req, res, next){ res.header('Access-Control-Allow-Origin', req.headers.origin); res.header('Access-Control-Allow-Credentials', "true"); res.header('Access-Control-Allow-Methods', req.method); res.header('Access-Control-Allow-Headers', 'X-Requested-With, Content-Length, Content-Type, Accept, Authorization, csrf-token'); res.send(200); }); app.use(cors(corsOptions));
API控制器响应代码
// 端点:GET https://apihost.mycompany.com/auth/info const whiteListOrigin = ['https://livefrontend.server.com','http://192.168.1.200:3000']; const allowedOrigin = whiteListOrigin.includes(req.headers.origin)?reqOrigin:whiteListOrigin[0]; const whiteListReqMethods = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']; const allowedReqMethod = whiteListReqMethods.includes(req.method)?reqMethod:whiteListReqMethods[0]; res .status(statusCode) .header("Access-Control-Allow-Origin", allowedOrigin) .header("Access-Control-Allow-Credentials", "true") .header("Access-Control-Allow-Methods", allowedReqMethod) .header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, csrf-token") .cookie('token', token, options) .json({ success: true, token });
浏览器报错信息
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://apihost.mycompany.com/auth/info. (Reason: CORS request did not succeed). Status code: (null).
问题修复方案
1. 解决HTTP与HTTPS混合请求限制
前端使用HTTP协议,后端API使用HTTPS,浏览器默认禁止这种混合内容环境下的带凭证跨域请求,这是核心原因之一。
- 修复:将前端Web服务器切换为HTTPS,保持前后端协议一致。
2. 移除冲突的CORS配置
代码中同时存在自定义的OPTIONS请求处理和cors中间件,两者配置不一致会导致预检请求失败:
- 自定义OPTIONS响应返回200状态,但
corsOptions指定了optionsSuccessStatus: 204 - 自定义响应的
Access-Control-Allow-Headers与corsOptions中的allowedHeaders不匹配(自定义为csrf-token,配置为x-csrf-token) - 修复:删除自定义的
app.options("*")处理代码,完全依赖cors中间件处理预检请求。
3. 删除控制器中重复的CORS头设置
Express控制器中重复设置CORS头,会与cors中间件的输出冲突,导致浏览器解析异常:
- 修复:删除控制器中所有
res.header("Access-Control-*")相关代码,由cors中间件统一管理跨域响应头。
4. 修正控制器中的变量错误
控制器代码中存在变量引用错误:allowedOrigin判断时使用了未定义的reqOrigin,导致跨域源校验逻辑错误:
- 修复:将变量修正为
req.headers.origin:
const allowedOrigin = whiteListOrigin.includes(req.headers.origin) ? req.headers.origin : whiteListOrigin[0];
5. 检查Nginx反向代理配置
确保Nginx正确转发请求到Node.js服务,并传递必要的请求头:
- 在Nginx配置中添加以下参数:
location / { proxy_set_header Origin $http_origin; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_pass http://localhost:你的Node服务端口; }
- 确保Nginx没有拦截OPTIONS请求,允许所有HTTP方法通过。
内容的提问来源于stack exchange,提问作者nomib
相关产品推荐
相关产品推荐

