在 Node.js 中为多个域启用 Access-Control-Allow-Origin [重复]

Posted

技术标签:

【中文标题】在 Node.js 中为多个域启用 Access-Control-Allow-Origin [重复]【英文标题】:Enable Access-Control-Allow-Origin for multiple domains in Node.js [duplicate] 【发布时间】:2014-09-13 21:19:53 【问题描述】:

我正在尝试在 node.js 中允许 CORS,但问题是如果设置了 Access-Control-Allow-Credentials,我无法将 * 设置为 Access-Control-Allow-Origin

规范还说我不能为Access-Control-Allow-Origin 做一个数组或逗号分隔值,建议的方法是做类似于Access-Control-Allow-Origin Multiple Origin Domains? 的事情

但我似乎不能在 node.js 中这样做

["http://example.com:9001", "http://example.com:5001"].map(domain => 
  res.setHeader("Access-Control-Allow-Origin", domain);
);
res.header("Access-Control-Allow-Credentials", true);

这里的问题是它被数组中的最后一个值覆盖,所以标题将设置为res.setHeader("Access-Control-Allow-Origin", "http://example.com:5001");

来自客户端浏览器的错误:

XMLHttpRequest 无法加载 http://example.com:9090/api/sync。这 “Access-Control-Allow-Origin”标头有一个值 'http://example.com:5001' 不等于提供的来源。 因此,不允许访问 Origin 'http://example.com:9001'。

【问题讨论】:

【参考方案1】:

这是我在我的 express 应用程序中使用的,以允许多个来源

app.use((req, res, next) => 
  const allowedOrigins = ['http://127.0.0.1:8020', 'http://localhost:8020', 'http://127.0.0.1:9000', 'http://localhost:9000'];
  const origin = req.headers.origin;
  if (allowedOrigins.includes(origin)) 
       res.setHeader('Access-Control-Allow-Origin', origin);
  
  //res.header('Access-Control-Allow-Origin', 'http://127.0.0.1:8020');
  res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.header('Access-Control-Allow-Credentials', true);
  return next();
);

【讨论】:

不错!这正是我需要的! res.header 和 res.setHeader 有区别吗? 查询:你在next()之前写return的原因是什么,不是自动调用next并发送请求到下一个中​​间件? @pro.mean 这里的return next() 将确保app.use 将返回next 回调返回的任何内容。只是next() 仍会调用回调,但不会将回调的返回值提供给app.use 的调用者。除非你知道什么叫app.use 下栈,以及next 处理函数是什么上栈,否则你无法知道是否有必要。 像这样让 options 方法的中间件更有意义,而不是拦截每个调用。请记住,这仅适用于使用 preflight 的 CORS 请求:app.options("*", function(req, res, next) ...【参考方案2】:

不确定这是否为时已晚,但我通过设置解决了它: res.setHeader("Access-Control-Allow-Origin", req.headers.origin);

这将简单地允许每个连接,因为 headers.origin 将随每个查询一起发送。

您可能需要编写一个函数来检查 req.headers.origin 是否是列入白名单的域(来自硬编码数组),如果该域存在于数组中,则简单地返回该域。

【讨论】:

这是一种过于复杂的说法 res.setHeader("Access-Control-Allow-Origin", "*"); @AlexanderGonchiy 不,不是。事实上,它完全不同,接受所有内容与将其动态设置为一个单一来源。以凭证为例。如果您想允许凭据,那么您的Access-Control-Allow-Origin 不能使用*,但它仍然可以使用此解决方案。感谢您的帖子 @cviejo 你是对的。这是我的确切用例。 对遇到此答案的人的警告;这几乎总是一个严重的安全漏洞。充其量它与 Access-Control-Allow-Origin: *.如果使用其他 CORS 标头,这可能会导致严重的跨站点请求伪造漏洞。漏洞跟踪数据库(例如 CVE)有大量与此答案推荐的完全匹配的漏洞。【参考方案3】:

根据您的 req.headers.origin 例如检查您的白名单

var origins = ['a.com', 'b.com', 'c.com', 'boobies.com'];
for(var i=0;i<origins.length;i++)
    var origin = origins[i];
    if(req.headers.origin.indexOf(origin) > -1) 
         res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
         return;
    
    // else, tough cookies. 

享受吧。

【讨论】:

* 请注意,此解决方案不处理 *.boobies.com 或 *, 域。 我不确定代码是否完全正确。但它帮助我实现了自己的......所以+1。【参考方案4】:

这是一个简单的中间件函数,用于从白名单中提供正确的 CORS 标头。将此设置在您的快速应用顶部附近将允许您的所有路线在提供内容之前从白名单中设置正确的标题。

app.use(function(req, res, next)
  var whitelist = ['localhost:4000', 'localhost:3000', 'anydomain.com']
  var host = req.get('host');

  whitelist.forEach(function(val, key)
    if (host.indexOf(val) > -1)
      res.setHeader('Access-Control-Allow-Origin', host);
    
  )

  next();
);

【讨论】:

不确定自 2015 年以来情况是否发生了变化,但当我检查 req 时,req.get('host') 的值是服务器本身的 URL。如果请求来自服务器外部,这就是我们需要白名单的原因,req.get('origin')req.get('referrer') 存储发出请求的 URL。我看到两者之间的唯一区别是referrer 包含一个斜杠。

以上是关于在 Node.js 中为多个域启用 Access-Control-Allow-Origin [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Node.js---使用Express写接口

多个域上的 Node.js 使用 express.vhosts()

如何在具有不同域的同一 IP/服务器上托管多个 Node.js 站点?

在具有多个域的同一服务器上托管 PHP 和 Node.js 应用程序

Node.js配合node-http-proxy解决本地开发ajax跨域问题

一个简单的node.js