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

85,783

Solution 1

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

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

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

mdn docs xhr.withCredentials

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

Solution 4

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

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())
Share:
85,783

Related videos on Youtube

Jamie Folsom
Author by

Jamie Folsom

Digital Humanities web application developer and software architect, working with faculty and staff at institutions of higher learning in the US, Canada and Europe (so far). Primarily using ruby, rails, javascript, postgresql and related technologies.

Updated on April 22, 2021

Comments

  • Jamie Folsom
    Jamie Folsom about 3 years

    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.

    • Ulysses Alves
      Ulysses Alves almost 8 years
      I'm getting this error in a code I didn't wrote, but I don't understand the need of a handler for the OPTIONS method. Could someone please help me to understand why not handling just the POST method instead of handling both POST and OPTIONS method?
    • Danny
      Danny over 5 years
      Might also want to include PATCH if you will use it instead of PUT to update a resource
  • Michal
    Michal over 11 years
    The reason it did is because you need to have it defined before the app.use(app.router); Cheers!
  • Aldo
    Aldo over 11 years
    In my case, next POST is not being called after sending back res.send(200) when req.method == 'OPTIONS'. am I missing anything else ?
  • Olegas
    Olegas over 11 years
    2Aldo: Code needed. May be you forgot some headers? If your client is not sending a POST after your server is correctly served a preflight OPTIONS request, try to check developer tools console. WebKit logs this kind of errors to web inspector's console.
  • Steven
    Steven over 9 years
    @ConnorLeech Very nice. I had been doing the allowCrossDomain approach as above and was tired of dealing with all that header mgmt. Also - since we only needed CORS for dev, wasn't making any sense to devote so many cycles to figuring out what was going on. Glad there is node.js support for easily allowing this.
  • drmrbrewer
    drmrbrewer over 6 years
    @ConnorLeech I think you should add your comment as an answer... works like a treat, and it's nice and simple
  • Alan
    Alan over 6 years
    Yes that was the problem with me. Could you be more specific how you solved problem. I am still in development still and am running on Express.js w/node cors package.
  • CatBrownie
    CatBrownie over 6 years
    @alan I was using promises to verifying the token in my application, some how if the JWT secret is not defined, the promise will never resolve, here's the code I was using if you need further reference.
  • Alan
    Alan over 6 years
    Thanks for responding. I will look over code. By secret I assume you are talking about the second private key. I am using oauth2.
  • alphanumeric0101
    alphanumeric0101 about 6 years
    I will add that any failing promise will produce this misleading error! I had to be explicit about a Node version being used or else my database calls (mongo) were simply hanging and the only thing the browser could tell me was 503 and then some Cors related silliness. This error really confused me for the longest as I had app.use(cors()); going.
  • brunelli
    brunelli about 3 years
    @CatBrownie, thanks for this answer. Exactly what I needed!