为什么不将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块中设置标题?

村村2020/03/30 17:29:28

如果我是@OP,我会更改我的编程范例。

假设由于要向localhost或类似请求而使这些CORS被阻止。

最终,如果您要部署到像Google Cloud Platformor Herokuor这样的生产视蛋白,则无需担心诸如允许原产地之类的CORS或生产中的任何东西。

因此,在测试服务器时,只需使用它即可,postman并且在部署服务器然后在客户端上工作之后,不会阻止CORS。

2020/03/30 17:29:28

您可以使用Express中间件,阻止您的域和方法。

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", process.env.DOMAIN); // update to match the domain you will make the request from
  res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
  res.header(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept"
  );
  next();
});
JinJin2020/03/30 17:29:28

使用Express Middleware非常适合我。如果您已经在使用Express,则只需添加以下中间件规则。它应该开始工作。

app.all("/api/*", function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
  res.header("Access-Control-Allow-Methods", "GET, PUT, POST");
  return next();
});

app.all("/api/*", function(req, res, next) {
  if (req.method.toLowerCase() !== "options") {
    return next();
  }
  return res.send(204);
});

参考

Tony凯2020/03/30 17:29:27

在我index.js我补充说:

app.use((req, res, next) => {
   res.header("Access-Control-Allow-Origin", "*");
   res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
   res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
   next();
}) 
飞云2020/03/30 17:29:27

做这样的事情:

app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});
猴子2020/03/30 17:29:27

要回答您的主要问题,如果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预检请求》