允许对Heroku上的Express / Node.js应用程序进行CORS REST请求


97

我已经在用于node.js的快速框架上编写了REST API,该API可以处理来自Chrome中的js控制台的请求以及URL栏等。域(CORS)。

由javascript前端自动发出的第一个请求是对/ api / search?uri =的,并且似乎对“预检” OPTIONS请求失败。

在我的express应用中,我使用以下方法添加了CORS标头:

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

    // intercept OPTIONS method
    if ('OPTIONS' == req.method) {
      res.send(200);
    }
    else {
      next();
    }
};

和:

app.configure(function () {
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(allowCrossDomain);
  app.use(express.static(path.join(application_root, "public")));
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

从Chrome控制台中,我得到以下标题:

请求网址:http://furious-night-5419.herokuapp.com/api/search?uri = http%3A%2F%2Flocalhost%3A5000%2Fcollections%2F1%2Fdocuments%2F1

请求方法:OPTIONS

状态码:200 OK

请求标题

Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:origin, x-annotator-auth-token, accept
Access-Control-Request-Method:GET
Connection:keep-alive
Host:furious-night-5419.herokuapp.com
Origin:http://localhost:5000
Referer:http://localhost:5000/collections/1/documents/1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5

查询字符串参数

uri:http://localhost:5000/collections/1/documents/1

响应标题

Allow:GET
Connection:keep-alive
Content-Length:3
Content-Type:text/html; charset=utf-8
X-Powered-By:Express

这看起来像API应用程序发送的标题不足吗?

谢谢。


我在未编写的代码中遇到此错误,但是我不理解该方法需要处理程序OPTIONS。有人可以帮我理解为什么不只处理POST方法而不是同时处理POST OPTIONS方法吗?
尤利西斯·阿尔维斯

可能还想包括PATCH是否使用它而不是PUT更新资源
Danny

Answers:


66

我已经在干净的ExpressJS应用上检查了您的代码,它正常工作。

尝试将您app.use(allowCrossDomain)移至配置功能的顶部。


8
这样做的原因是因为您需要在app.use(app.router);干杯之前定义它!
米哈尔(Michal)2012年

在我的情况下,当req.method =='OPTIONS'时,在发回res.send(200)之后不调用下一个POST。我还有什么想念的吗?
Aldo 2012年

2Aldo:需要代码。可能您忘记了一些标题吗?如果在服务器正确收到预检选项请求后,客户端未发送POST,请尝试检查开发人员工具控制台。WebKit将这种错误记录到Web检查器的控制台。
Olegas 2012年

1
@ConnorLeech非常好。我一直在做上述的allowCrossDomain方法,并且厌倦了处理所有标头mgmt。而且-由于我们只需要CORS进行开发,因此花那么多周期来弄清楚发生了什么事情没有任何意义。很高兴提供了node.js支持,可轻松实现这一点。
史蒂文(Steven)2015年

1
@ConnorLeech我认为您应该添加您的评论作为答案...就像一种享受,它很好而且很简单
drmrbrewer

4

为了支持带有凭据的Cookie,您需要此行 xhr.withCredentials = true;

mdn docs xhr.withCredentials

在Express Server中,在所有其他块之前添加此块

`app.all('*', function(req, res, next) {
     var origin = req.get('origin'); 
     res.header('Access-Control-Allow-Origin', origin);
     res.header("Access-Control-Allow-Headers", "X-Requested-With");
     res.header('Access-Control-Allow-Headers', 'Content-Type');
     next();
});`

4

我将其添加为答案仅是因为原始帖子被添加为评论,因此,当我第一次浏览此页面时,它确实被您的忽略。

正如@ConnorLeech在他对上面接受的答案的评论中指出的那样,有一个非常方便的npm软件包,叫做cors,这并不奇怪。它的用法很简单var cors = require('cors'); app.use(cors());(再次从Leech先生的回答中得知),也可以按照其文档中概述的更严格,更可配置的方式进行应用。

可能值得指出的是,我上面提到的原始评论是在2014年提出的。现在是2019年,而在npm软件包的github页面上,回购就在9天前进行了更新。


0

对于大多数浏览此问题的人来说,情况可能并非如此,但我也遇到了同样的问题,解决方案与无关CORS

事实证明,string在环境变量中未定义JSON Web令牌机密,因此无法对令牌进行签名。这会导致任何POST依赖于检查或签署令牌以获取超时并返回503错误的请求,从而告诉浏览器出了点问题CORS,事实并非如此。在Heroku中添加环境变量解决了该问题。

我希望这可以帮助别人。


是的,这就是我的问题。您能否更具体地解决问题。我仍在开发中,并且在带有节点cors包的Express.js上运行。
艾伦(Alan)

@alan我正在使用promise来验证应用程序中的令牌,如果未定义JWT机密,promise将永远无法解决,这是我正在使用的代码(如果需要进一步参考)。
CatBrownie

感谢您的回应。我会看一下代码。秘密地说,我假设您正在谈论第二个私钥。我正在使用oauth2。
艾伦(Alan)

我还要补充一点,任何失败的承诺都会产生这种误导性错误!我必须明确说明正在使用的Node版本,否则我的数据库调用(mongo)只是挂起了,浏览器只能告诉我的是503,然后是一些与Cors相关的愚蠢行为。这个错误使我感到困惑的时间最长app.use(cors());
alphanumeric0101

0

在此处输入图片说明

请按照以下步骤操作:

npm install cors --save

在您的根js文件中:

 var express = require('express') 
 var cors = require('cors')
 var app = express()
 app.use(cors())
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.