No 'Access-Control-Allow-Origin' - Node / Apache Port Issue
Asked Answered
H

17

374

i've created a small API using Node/Express and trying to pull data using Angularjs but as my html page is running under apache on localhost:8888 and node API is listen on port 3000, i am getting the No 'Access-Control-Allow-Origin'. I tried using node-http-proxy and Vhosts Apache but not having much succes, please see full error and code below.

XMLHttpRequest cannot load localhost:3000. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:8888' is therefore not allowed access."

// Api Using Node/Express    
var express = require('express');
var app = express();
var contractors = [
    {   
     "id": "1", 
        "name": "Joe Blogg",
        "Weeks": 3,
        "Photo": "1.png"
    }
];

app.use(express.bodyParser());

app.get('/', function(req, res) {
  res.json(contractors);
});
app.listen(process.env.PORT || 3000);
console.log('Server is running on Port 3000')

Angular code

angular.module('contractorsApp', [])
.controller('ContractorsCtrl', function($scope, $http,$routeParams) {

   $http.get('localhost:3000').then(function(response) {
       var data = response.data;
       $scope.contractors = data;
   })

HTML

<body ng-app="contractorsApp">
    <div ng-controller="ContractorsCtrl"> 
        <ul>
            <li ng-repeat="person in contractors">{{person.name}}</li>
        </ul>
    </div>
</body>
However answered 19/8, 2013 at 9:22 Comment(1)
E
838

Try adding the following middleware to your NodeJS/Express app (I have added some comments for your convenience):

// Add headers before the routes are defined
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8888');

    // 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');

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

(You might need to use 127.0.0.1 instead of localhost.)

Egidius answered 19/8, 2013 at 10:23 Comment(21)
Can you help specify exactly where that goes? I have the following code in my server. Does it go right after this? var app = require('express')() , server = require('http').createServer(app) , io = require('socket.io').listen(server) , request = require("request") , url = require("url"); server.listen(6969); // does it go here? on a new line?Boffa
It is a middleware function. You can put it after the require lines and before the server.listen line. Hope that helps!Egidius
@Egidius do i have to change the app.get('/', function(req, res) to ...function(req, res, next) ?Lutes
@SangramSingh Yes, the next argument is optional but you need to specify it in case you use it inside your function.Egidius
You are my favorite person ever right now. Thank you. Can we add a note that this code has to happen before the routes are defined for noobs like me?Islington
What if i am using 3rd Party API ? I can't add "Allow Access" on their server. You are showing example of local project. I am having same issue but with my request is goes to another website url. How to fix it any idea ?Reggiereggis
@Reggiereggis - CORS was created to prevent client from unauthorized access. If you want to have access, you need the 3rd party app owner to add you to his authorized users. Else I can simply create my own MyGoogle website, provide search query, and present the results as my own.Julenejulep
@Islington -> Thanks for your comment. I was adding this line after the routes were defined. :/ It works fine after putting the above code, just after creating the app object.Julenejulep
How to make this work while using the request module?Hultin
@RohitTigga did you ever find how to get this working with request?Chavez
Wow buddy this is the ultimate hat trick, thanks man, I would never guess this solution.Tectonic
It did not work in my case. Still getting this error: "Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'abc.xyz.net:212' is therefore not allowed access. The response had HTTP status code 500."Seibold
perfect, for testing I replaced 'localhost:8888' with '*' not safe, but great for testingMongolic
@JohanHoeksma is there a reason why that isn't so safe? How did you setup for production?Deposal
So any origin can connect now. For a localhost it's not a problem. On a server I think you don't want it...Mongolic
Thank you - I was tearing my hair out trying to get this working. Worth noting that the website is case sensitive.Jhelum
I wish I bumped into this 4 hours ago!Quartas
How to fix this in hapiJSPhyllode
I ran into this problem with a POST request but it had to do with the upload size being too large. It was a very misleading error.Marsiella
How do we allow for all origins instead of just localhost:8888 ? Is adding an asterisk instead of url like res.setHeader('Access-Control-Allow-Origin', '*'); a valid way ?W
this worked thaksHighlander
A
139

Accepted answer is fine, in case you prefer something shorter, you may use a plugin called cors available for Express.js.

It's simple to use, for this particular case:

var cors = require('cors');

// use it before all route definitions
app.use(cors({origin: 'http://localhost:8888'}));

(You might need to use 127.0.0.1 instead of localhost.)

The request origin needs to match the allowed origin(s), and you can also have multiple of them:

app.use(
  cors({origin: ['http://localhost:8888', 'http://127.0.0.1:8888']})
);
Agrippina answered 18/12, 2015 at 0:11 Comment(7)
I had to use {origin: 'null'} for it to work... Apparently, my browser sends null as the origin?Mantellone
Why reinvent the wheel. I am always for a packaged solution compared to code snippetFrowst
sweet little library that handled my use case of wanting different methods from different origins quite nicely... and less code fatigue for the next guy looking at it.Charactery
Thanks, app.use(cors({origin: '*'})); worked for me, as per enable-cors.Gremial
I suggest having a look at the npm cors page to make better use of it. It made things very clear for me =).Bouillabaisse
How to fixed this in HapiJSPhyllode
I'm new, how to input multiple origin with above code?Riggins
S
45

Another way, is simply add the headers to your route:

router.get('/', function(req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE'); // If needed
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); // If needed
    res.setHeader('Access-Control-Allow-Credentials', true); // If needed

    res.send('cors problem fixed:)');
});
Silence answered 26/11, 2016 at 16:14 Comment(1)
) of smiley confused meSheba
C
23

The top answer worked fine for me, except that I needed to whitelist more than one domain.

Also, top answer suffers from the fact that OPTIONS request isn't handled by middleware and you don't get it automatically.

I store whitelisted domains as allowed_origins in Express configuration and put the correct domain according to origin header since Access-Control-Allow-Origin doesn't allow specifying more than one domain.

Here's what I ended up with:

var _ = require('underscore');

function allowCrossDomain(req, res, next) {
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');

  var origin = req.headers.origin;
  if (_.contains(app.get('allowed_origins'), origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
  }

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

app.configure(function () {
  app.use(express.logger());
  app.use(express.bodyParser());
  app.use(allowCrossDomain);
});
Crowned answered 28/3, 2014 at 17:30 Comment(1)
Is this the same 'if (app.get('allowed origins').indexOf(origin)!==-1)?'?Orlan
A
16

The answer code allow only to localhost:8888. This code can't be deployed to the production, or different server and port name.

To get it working for all sources, use this instead:

// Add headers
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', '*');

    // 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');

    // 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();
});
Anonym answered 6/7, 2016 at 17:31 Comment(3)
This does not work for me! " * is not a valid origin ". It seems the * character is not recognized as a wildcard.Condensed
It works for me. i.e. using wild card '*'. works both for chrome and safari.Cytosine
Thanks ;) Works fineBraque
U
15

Install cors dependency in your project:

npm i --save cors

Add to your server configuration file the following:

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

It works for me with 2.8.4 cors version.

Unmade answered 29/8, 2018 at 9:21 Comment(3)
"cors": "^2.8.5", "express": "^4.16.3", works fine just with the line @monikaja suggested. Thanks!Simonasimonds
What this does is to enable all origins/domains to access the app which is something you usually don't want to do. Instead specify just the allowed domains.Solidarity
After 4-5 hours of searching, this is the only solution that actually works for me. ThanksLacefield
S
15

Hi this happens when the front end and backend is running on different ports. The browser blocks the responses from the backend due to the absence on CORS headers. The solution is to make add the CORS headers in the backend request. The easiest way is to use cors npm package.

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

This will enable CORS headers in all your request. For more information you can refer to cors documentation

https://www.npmjs.com/package/cors

Soggy answered 18/8, 2019 at 14:1 Comment(0)
O
10

This worked for me.

app.get('/', function (req, res) {

    res.header("Access-Control-Allow-Origin", "*");
    res.send('hello world')
})

You can change * to fit your needs. Hope this can help.

Oleo answered 15/12, 2018 at 11:31 Comment(0)
C
10

All the other answers didn't work for me. (including cors package, or setting headers through middleware)

For socket.io 3^ this worked without any extra packages.

const express = require('express');
const app = express();

const server = require('http').createServer(app);
const io = require('socket.io')(server, {
    cors: {
        origin: "*",
        methods: ["GET", "POST"]
    }
});
Capetian answered 1/1, 2021 at 17:43 Comment(1)
This is a best reply ever! Worked with socketio. ThanksCellule
G
5
app.all('*', function(req, res,next) {
    /**
     * Response settings
     * @type {Object}
     */
    var responseSettings = {
        "AccessControlAllowOrigin": req.headers.origin,
        "AccessControlAllowHeaders": "Content-Type,X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5,  Date, X-Api-Version, X-File-Name",
        "AccessControlAllowMethods": "POST, GET, PUT, DELETE, OPTIONS",
        "AccessControlAllowCredentials": true
    };

    /**
     * Headers
     */
    res.header("Access-Control-Allow-Credentials", responseSettings.AccessControlAllowCredentials);
    res.header("Access-Control-Allow-Origin",  responseSettings.AccessControlAllowOrigin);
    res.header("Access-Control-Allow-Headers", (req.headers['access-control-request-headers']) ? req.headers['access-control-request-headers'] : "x-requested-with");
    res.header("Access-Control-Allow-Methods", (req.headers['access-control-request-method']) ? req.headers['access-control-request-method'] : responseSettings.AccessControlAllowMethods);

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


});
Greene answered 21/12, 2015 at 12:51 Comment(1)
Isn't this approach much simpler? https://mcmap.net/q/65846/-no-39-access-control-allow-origin-39-node-apache-port-issueMarvelous
F
4

Add following code in app.js of NODEJ Restful api to avoid "Access-Control-Allow-Origin" error in angular 6 or any other framework

var express = require('express');
var app = express();

var cors = require('cors');
var bodyParser = require('body-parser');

//enables cors
app.use(cors({
  'allowedHeaders': ['sessionId', 'Content-Type'],
  'exposedHeaders': ['sessionId'],
  'origin': '*',
  'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
  'preflightContinue': false
}));
Friar answered 22/5, 2018 at 14:55 Comment(0)
O
4

You could use cors package to handle it.

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

app.use(cors())

for setting the specific origin

app.use(cors({origin: 'http://localhost:8080'}));

know more

Orfield answered 8/8, 2021 at 5:2 Comment(0)
D
2

You can use "$http.jsonp"

OR

Below is the work around for chrome for local testing

You need to open your chrome with following command. (Press window+R)

Chrome.exe --allow-file-access-from-files

Note : Your chrome must not be open. When you run this command chrome will open automatically.

If you are entering this command in command prompt then select your chrome installation directory then use this command.

Below script code for open chrome in MAC with "--allow-file-access-from-files"

set chromePath to POSIX path of "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" 
set switch to " --allow-file-access-from-files"
do shell script (quoted form of chromePath) & switch & " > /dev/null 2>&1 &"

second options

You can just use open(1) to add the flags: open -a 'Google Chrome' --args --allow-file-access-from-files

Demented answered 19/8, 2013 at 9:30 Comment(3)
How about on MAC ?? Chrome.exe --allow-file-access-from-filesHowever
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --allow-file-access-from-files manage to open chrome but the message is still showing "XMLHttpRequest cannot load localhost:3000. Origin localhost:8888 is not allowed by Access-Control-Allow-Origin. "However
+1 I can confirm this works with the Mac option using 'open'. My case is a little different as I'm simply testing a completely downloaded site that accesses some local JSON files.Flambeau
M
1

/**
 * Allow cross origin to access our /public directory from any site.
 * Make sure this header option is defined before defining of static path to /public directory
 */
expressApp.use('/public',function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    // Request headers you wish to allow
    res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    // Set to true if you need the website to include cookies in the requests sent
    res.setHeader('Access-Control-Allow-Credentials', true);
    // Pass to next layer of middleware
    next();
});


/**
 * Server is about set up. Now track for css/js/images request from the 
 * browser directly. Send static resources from "./public" directory. 
 */
expressApp.use('/public', express.static(path.join(__dirname, 'public')));
If you want to set Access-Control-Allow-Origin to a specific static directory you can set the following.
Mettah answered 2/7, 2016 at 6:18 Comment(0)
T
1

Apart from all listed answers, I had the same error

I have both access to frontend and backend, I already added cors module app.use(cors()); Still, I was struggling with this error.

After some debugging, I found the issue. When I upload a media which size was more than 1 MB then the error was thrown by Nginx server

<html>

<head>
    <title>413 Request Entity Too Large</title>
</head>

<body>
    <center>
        <h1>413 Request Entity Too Large</h1>
    </center>
    <hr>
    <center>nginx/1.18.0</center>
</body>

</html>

But in the console of frontend, I found the error

Access to XMLHttpRequest at 'https://api.yourbackend.com' from origin 'https://web.yourfromntend.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

So It makes confusion here. But the route cause of this error was from nginx configuration. It's just because the directive client_max_body_size value has been set to 0 by default. It determines what the allowable HTTP request size can be is client_max_body_size. This directive may already be defined in your nginx.conf file located at /etc/nginx/nginx.conf Now you need to add/edit the value of the directive client_max_body_size either at http or server.

server {
    client_max_body_size 100M;
    ...
}

Once you have set your desired value, save your changes and reload Nginx: service nginx reload

After these changes, It's working well

REFERENCE: https://www.keycdn.com/support/413-request-entity-too-large#:~:text=%23,processed%20by%20the%20web%20server.&text=An%20example%20request%2C%20that%20may,e.g.%20a%20large%20media%20file).

Teevens answered 3/7, 2020 at 19:34 Comment(0)
A
0

We'll see if the top 2 answers accept my edit, but it's very likely you're gonna have to either add or use 127.0.0.1 instead of localhost.

With the cors package, you're even able to use more than one allowed origin:

app.use(
  cors({ origin: ["http://localhost:8888", "http://127.0.0.1:8888"] })
);

And you could use origin: "*" if you wish to allow for anything.

For more info, do check out Web Dev Simplified's tutorial.

Aspa answered 13/9, 2022 at 13:42 Comment(0)
E
0

Accepted answer is probably fine. I haven't tried it. I preferred to use cors.

However, the simpler usage of cors mentioned here didn't work for me. It shouldn't work for you too as expected if you test it closely i.e. then you should be able to access from any domain and not only limited to whitelisted ones which it should be, i.e. it will look like it is working as you can access your backend but not only from the whitelisted domains as expected but any. I noticed that even though I was whitelisting only specific domains using the simpler method, app.use(cors({origin: ['http://localhost:8888', 'http://127.0.0.1:8888']})); or some other similar solution, I was literally able to access my backend from any domain (using thunder client, bash command, custom origin value, or even from another not-whitelisted machine). There is no mention of such exact example of simple usage in cors documentation as well (as of now) that skips the usage of corsOptions or such middleware.

But then I came up with this solution that is working as expected i.e. now I can only access from whitelisted domains and not from others.

Click HERE to find a detailed answer on how to use cors to whitelist specific domains i.e. allow only specific domains to access your backend endpoints securely. In your case, you will only need to modify this - ALLOWED_ORIGINS=https://foo.example1 https://foo.example2 to this - ALLOWED_ORIGINS=http://localhost:8888 http://127.0.0.1:8888

I have used cors recently. This is the better way which I could come up with that works well, has better control and security.

Excellency answered 10/10, 2023 at 8:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.