105

I'm trying to build a web server in node.js that will support cross-domain scripting, while still providing static files from a public directory. I'm using the express.js and am not really sure how to allow cross-domain scripting (Access-Control-Allow-Origin: *).

I saw this post, which I did not find helpful.

var express = require('express')
  , app = express.createServer();

app.get('/', function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    next();
});

app.configure(function () {
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(app.router);
});

app.configure('development', function () {

    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function () {


    var oneYear = 31557600000;
    //    app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler());
});

app.listen(8888);
console.log('express running at http://localhost:%d', 8888);
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Guy
  • 5,370
  • 6
  • 25
  • 30

8 Answers8

162

Check out the example from enable-cors.org:

In your ExpressJS app on node.js, do the following with your routes:

app.all('/', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  next();
 });

app.get('/', function(req, res, next) {
  // Handle the get for this route
});

app.post('/', function(req, res, next) {
 // Handle the post for this route
});

The first call (app.all) should be made before all the other routes in your app (or at least the ones you want to be CORS enabled).

[Edit]

If you want the headers to show up for static files as well, try this (make sure it's before the call to use(express.static()):

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  next();
});

I tested this with your code, and got the headers on assets from the public directory:

var express = require('express')
  , app = express.createServer();

app.configure(function () {
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(function(req, res, next) {
      res.header("Access-Control-Allow-Origin", "*");
      res.header("Access-Control-Allow-Headers", "X-Requested-With");
      next();
    });
    app.use(app.router);
});

app.configure('development', function () {
    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function () {
    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler());
});

app.listen(8888);
console.log('express running at http://localhost:%d', 8888);

You could, of course, package the function up into a module so you can do something like

// cors.js

module.exports = function() {
  return function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    next();
  };
}

// server.js

cors = require('./cors');
app.use(cors());
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • Hey, thanks for your response. I did what you suggested (first part, but still don't see any different in the request headers) I've attached my current code above. can you explain how I can integrate the rest of your solution to that? – Guy Jun 25 '12 at 16:10
  • 1
    I'm surprised that, since you're `use`ing `app.router` before `express.static` that it doesn't modify the headers for static files; in any case, I've updated my answer so that it works. – Michelle Tilley Jun 25 '12 at 16:56
  • Thanks! I see that you are right. The assets are get from server are with the requested headers. I may have not been clear about my real issue. I'm trying to make an API call to an external server with get command. and that's where I get the error: XMLHttpRequest cannot load http://www.SOMEURL.com. Origin http://localhost:8888 is not allowed by Access-Control-Allow-Origin. – Guy Jun 25 '12 at 17:17
  • I may be misunderstanding. Are you in control of the server at SOMEURL.com? – Michelle Tilley Jun 25 '12 at 22:30
  • Sorry I completely understand your answer now. Thanks a lot. I appreciate your help :) – Guy Jun 26 '12 at 12:49
  • I'm having trouble accessing the post data for XDomainRequest() requests made from IE9. I'm using `var obj = request.body;` This works fine for all post requests made via `xmlHttpRequest()` Any ideas? – singh1469 Jun 11 '14 at 20:55
  • ok, found the answer. `xDomainRequest` **does not send a `content-type` header** and bodyParser cannot work without it. To fix, simply add a default `content-type` header using middleware. – singh1469 Jun 12 '14 at 13:47
  • how do you restrict the api call to be made from one other location? – SuperUberDuper Jan 09 '17 at 10:21
  • Having had the same issue as described by the question owner, I found that ONLY adding these headers in the server side wouldn't work. For some reason, by changing code in the CLIENT side and making a request to `"http://localhost/"` instead of `"localhost/"` made it work. – Bersan Aug 26 '19 at 00:31
61

Following @Michelle Tilley solution, apparently it didn't work for me at first. Not sure why, maybe I am using chrome and different version of node. After did some minor tweaks, it is working for me now.

app.all('*', function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

In case someone facing similar issue as mine, this might be helpful.

Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
TonyTakeshi
  • 5,869
  • 10
  • 51
  • 72
  • Notice the app.all vs app.get. It is OPTIONS request not GET – Shimon Doodkin Nov 12 '12 at 19:12
  • This works for me (I'm fetching objects using Backbone). I'm trying to figure out if it will work in IE 8... seems like it should, but I don't know if anything special is required for this "XDomainRequest" thing ... https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS#Browser_compatibility – Adam Loving May 29 '13 at 15:31
  • SOME INFO FOR FUTURE USERS: I am re-directing my domain name to a heroku repo which is why I was running into this issue. Anyways, the first answer worked locally but not after I pushed it to heroku. However this answer worked after pushing to heroku. – khollenbeck Jun 13 '14 at 19:46
  • @KrisHollenbeck This doesnt work for me on heroku, did you do anything else? – Ben Craig Jul 25 '14 at 15:54
  • @BenCraig, No, but it actually stopped working for me after the first try. So I am actually still having this problem as well. – khollenbeck Jul 25 '14 at 16:08
  • @KrisHollenbeck dang. I sent in a heroku ticket, I hope they have some sort of solution – Ben Craig Jul 25 '14 at 16:54
  • @KrisHollenbeck I got mine working (it was just hrefs), by adding target="_blank" – Ben Craig Jul 25 '14 at 17:51
  • @BenCraig, I will have to give that a try. – khollenbeck Jul 25 '14 at 18:23
13

Try to this cors npm modules.

var cors = require('cors')

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

This module provides many features to fine tune cors setting such as domain whitelisting, enabling cors for specific apis etc.

Deepak Bansal
  • 115
  • 1
  • 5
Zahidur Rahman
  • 1,688
  • 2
  • 20
  • 30
2

I use this:

var app = express();

app
.use(function(req, res, next){
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With');
    next();
})
.options('*', function(req, res, next){
    res.end();
})
;

h.readFiles('controllers').forEach(function(file){
  require('./controllers/' + file)(app);
})
;

app.listen(port);
console.log('server listening on port ' + port);

this code assumes that your controllers are located in the controllers directory. each file in this directory should be something like this:

module.exports = function(app){

    app.get('/', function(req, res, next){
        res.end('hi');
    });

}
Elmer
  • 9,147
  • 2
  • 48
  • 38
1

Recommend using the cors express module. This allows you to whitelist domains, allow/restrict domains specifically to routes, etc.,

Jerome Anthony
  • 7,823
  • 2
  • 40
  • 31
0

You must set Access-Control-Allow-Credentials: true, if you want to use "cookie" via "Credentials"

app.all('*', function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});
hui
  • 591
  • 7
  • 22
0
app.use(function(req, res, next) {
var allowedOrigins = [
  "http://localhost:4200"
];
var origin = req.headers.origin;
console.log(origin)
console.log(allowedOrigins.indexOf(origin) > -1)
// Website you wish to allow to
if (allowedOrigins.indexOf(origin) > -1) {
  res.setHeader("Access-Control-Allow-Origin", origin);
}

// res.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");

// Request methods you wish to allow
res.setHeader(
  "Access-Control-Allow-Methods",
  "GET, POST, OPTIONS, PUT, PATCH, DELETE"
);

// Request headers you wish to allow
res.setHeader(
  "Access-Control-Allow-Headers",
  "X-Requested-With,content-type,Authorization"
);

// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader("Access-Control-Allow-Credentials", true);

// Pass to next layer of middleware
next();

});

Add this code in your index.js or server.js file and change the allowed origin array according to your requirement.

-9

One additional step I needed to take was to switch my URL from http://localhost to http://127.0.0.0