Allow CORS REST request to a Express/Node.js application on Heroku

node.jsRestHerokuExpressCors

node.js Problem Overview


I've written a REST API on the express framework for node.js that works for requests from the js console in Chrome, and URL bar, etc. I'm now trying to get it working for requests from another app, on a different domain (CORS).

The first request, made automatically by the javascript front end, is to /api/search?uri=, and appears to be failing on the "preflight" OPTIONS request.

In my express app, I am adding CORS headers, using:

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();
    }
};

and:

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 }));
});

From the Chrome console I get these headers:

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

Request Method:OPTIONS

Status Code:200 OK

Request Headers

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

Query String Parameters

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

Response Headers

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

Does this look like a lack of proper headers being sent by the API application?

Thanks.

node.js Solutions


Solution 1 - node.js

I've cheked your code on a clean ExpressJS app and it works just fine.

Try move your app.use(allowCrossDomain) to the top of configure function.

Solution 2 - node.js

I'm adding this as an answer only because the original post was put in as a comment and as such it got overlooked by yours truly the first time I went over this page.

As @ConnorLeech points out in his comment to the accepted answer above, there is a very handy npm package called, not surprisingly, cors. It's use is as simple as var cors = require('cors'); app.use(cors()); (again, cribbed from Mr. Leech's answer) and can also be applied in a stricter, more configurable fashion as outlined in their docs.

It may also be worth pointing out that the original comment I refer to above was made in 2014. It's 2019 now and looking at the npm package's github page the repo was updated as recently as nine days ago.

Solution 3 - node.js

for supporting cookies withCredentials you need this line xhr.withCredentials = true;

[mdn docs xhr.withCredentials][1]

In the Express Server add this block before all the other

`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();
});`

[1]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials "docs"

Solution 4 - node.js

It could not be the case for most people browsing this question but I had this exact same problem and the solution was not related to CORS.

Turns out that JSON Web Token secret string was not defined in the environment variables, so the token could not be signed. This caused to any POST request that relies on checking or signing a token to get a timeout and return a 503 error, telling the browser that there's something wrong in CORS, which it's not. Adding the environment variable in Heroku solved the issue.

I hope this helps someone.

Solution 5 - node.js

enter image description here

Follow the below steps:

> npm install cors --save

Inside your root js file:

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

Solution 6 - node.js

The Cors error could be a cover up for your actual error. Look in the logs of your heroku build to see your potential real error. Mine was this.

https://stackoverflow.com/questions/60048669/heroku-postgres-psql-fatal-no-pg-hba-conf-entry-for-host

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJamie FolsomView Question on Stackoverflow
Solution 1 - node.jsOlegasView Answer on Stackoverflow
Solution 2 - node.jsflyingaceView Answer on Stackoverflow
Solution 3 - node.jsdoron aviguyView Answer on Stackoverflow
Solution 4 - node.jsCatBrownieView Answer on Stackoverflow
Solution 5 - node.jsParidhi shahView Answer on Stackoverflow
Solution 6 - node.jsKudaView Answer on Stackoverflow