协慌网

登录 贡献 社区

为什么不将 CORS 标头添加到 OPTIONS 路由允许浏览器访问我的 API?

我正在尝试在使用 Express.js Web 框架的 Node.js 应用程序中支持 CORS。我已经阅读了有关如何处理此问题的 Google 小组讨论,并阅读了一些有关 CORS 工作原理的文章。首先,我做到了(代码是用 CoffeeScript 语法编写的):

app.options "*", (req, res) ->
  res.header 'Access-Control-Allow-Origin', '*'
  res.header 'Access-Control-Allow-Credentials', true
  # try: 'POST, GET, PUT, DELETE, OPTIONS'
  res.header 'Access-Control-Allow-Methods', 'GET, OPTIONS'
  # try: 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept'
  res.header 'Access-Control-Allow-Headers', 'Content-Type'
  # ...

它似乎不起作用。看来我的浏览器(Chrome)没有发送初始的 OPTIONS 请求。当我刚刚更新资源块时,我需要向以下站点提交跨域 GET 请求:

app.get "/somethingelse", (req, res) ->
  # ...
  res.header 'Access-Control-Allow-Origin', '*'
  res.header 'Access-Control-Allow-Credentials', true
  res.header 'Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS'
  res.header 'Access-Control-Allow-Headers', 'Content-Type'
  # ...

它可以工作(在 Chrome 中)。这也适用于 Safari。

我读过...

在实现 CORS 的浏览器中,每个跨域的 GET 或 POST 请求都带有一个 OPTIONS 请求,该请求检查 GET 或 POST 是否正常。

所以我的主要问题是,在我看来,这种情况怎么似乎没有发生?为什么不调用我的 app.options 块?为什么需要在主 app.get 块中设置标题?

答案

我发现最简单的方法是使用 node.js 包cors 。最简单的用法是:

var cors = require('cors')

var app = express()
app.use(cors())

当然,有很多方法可以根据您的需要配置行为。上面链接的页面显示了许多示例。

尝试将控制权传递给下一条匹配的路线。如果 Express 首先匹配 app.get 路由,则除非您这样做(否则请注意使用 next),否则它将不会继续进入选项路由:

app.get('somethingelse', function(req, res, next) {
    //..set headers etc.

    next();
});

在组织 CORS 方面,我将其放在对我来说很好的中间件中:

//CORS middleware
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', 'example.com');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    next();
}

//...
app.configure(function() {
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.session({ secret: 'cool beans' }));
    app.use(express.methodOverride());
    app.use(allowCrossDomain);
    app.use(app.router);
    app.use(express.static(__dirname + '/public'));
});

要回答您的主要问题,如果 POST 或 GET 中包含任何非简单的内容或标头,则 CORS 规范仅要求 OPTIONS 调用位于 POST 或 GET 之前。

需要 CORS 飞行前请求(OPTIONS 调用)的内容类型是除以下内容之外的任何内容类型:

  1. application/x-www-form-urlencoded
  2. multipart/form-data
  3. text/plain

除上面列出的内容类型外,任何其他内容类型都将触发飞行前请求。

至于标头,除以下内容外,任何请求标头都将触发飞行前请求:

  1. Accept
  2. Accept-Language
  3. Content-Language
  4. Content-Type
  5. DPR
  6. Save-Data
  7. Viewport-Width
  8. Width

其他任何请求标头都将触发飞行前请求。

因此,您可以添加一个自定义标头,例如: x-Trigger: CORS ,它应该触发飞行前请求并点击 OPTIONS 块。

请参阅《 MDN Web API 参考 - CORS 预检请求》