You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

前后端分离生产环境下跨域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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 05:45:40