Angular express.js CORS - node.js

I am using express 4.1.0, and angular 1.2.12.
My client-code looks like this:
$http.get(data_url + '/stickers.json')
.success(function (data, status, headers, config) {
// do stuff
})
.error(function (data, status, headers, config) {
console.log(status, config);
});
I have done all the correct express stuff, as far as I can tell:
var express = require('express'),
app = express();
app.use(function (req, res, next) {
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.set('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type,Accept');
next();
});
app.use(express.static(__dirname + '/webroot'));
app.listen(process.env.PORT || 5000);
I also tried cors module.
I am running my client-app on localhost, port 8000. The remote file is on heroku.
In all cases, I get this error in the console:
XMLHttpRequest cannot load http://<URL>/stickers.json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
When I access http://<URL>/stickers.json directly and look at returned headers, I see these:
Access-Control-Allow-Headers:X-Requested-With,content-type
Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin:*
Update:
If you'd like to look at it, I made a codepen, and a new heroku app with above server code.
Weirdly, it works fine, so now I am really confused. I think it must be express, because it stops working when I swap the URLs.
Update 2:
If I run the codepen with the URL from localhost running the original code, it also works. It must be something funny with heroku.

I got it! it needs to be http://*.herokuapp.com/, or it redirects. I was using *.heroku.com.

Related

new HttpHeaders().set() does not set headers - Ionic/Angular

I'm creating a little app using NodeJs and Ionic v3 and I'm stuck with CORS error:
Failed to load http://localhost:3000/crm/getAllClients: Response to
preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8100' is therefore not allowed
access.
I've set CORS in nodeJs like this:
app.use(cors());
To make HTTP request with Ionic I'm using :
import {HttpClient, HttpHeaders} from "#angular/common/http";
Here's my code in my Ionic service:
initHeaders() {
let headers = new HttpHeaders()
.set('Access-Control-Allow-Origin', "*")
.set("Content-Type", "application/json")
.set("Access-Control-Expose-Headers", "Content-Length");
return headers;
}
getAllClients () {
return this.http.get(this.domain + 'crm/getAllClients', {headers: this.initHeaders()});
}
Here are the headers with no header set:
Am I doing something wrong ?
I had a similar issue in the past. As far as I understand you are not doing anything wrong, your three headers are inside "Access-Control-Request-Headers" (in your screenshot under "Request Headers".
The browser joins all your CORS headers and puts them in "Access-Control-Request-Headers".
My bet is that there is a problem with the cors configuration in node. I would try something like this in you express app:
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Headers", "Access-Control-Expose-Headers, Content-Type, Accept");
next();
});
instead of using
app.use(cors())
Or check that you are writing app.use(cors()) before adding the routes, so that the routes are using cors.
My problem was that I called cors Middleware after I've set routes on my app.js in node !
// set it before routes !
app.use(cors());
app.use('/', index);
app.use('/crm', crm);

Unable to send http post with credentials to iis node server

I'm trying to send a http post request from my angular app to my node.js server with user credentials in order to log it.
Both are hosted in IIS (the node server with nodeiis) and both are configured to be authenticated by windows authentication.
My angular code:
var url = "http://myurl:15001/addItem";
this.http.post(url, {
"itemName": "SomeName",
"itemColor": "SomeColor"
}, {withCredentials: true}).subscribe(res =>{
console.log("Great, item was added");
})
My Node.js Code:
var app = express();
var allowCrossDomain = function (req, res, next){
res.header('Access-Control-Allow-Origin', "http://myurl") //Cannot be a wildcard because of the credentials.
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if(res.method == 'OPTIONS')
res.send(200);
else
next();
};
app.use(allowCrossDomain);
app.post('/addItem', function(req, res){
//Saves the item...
res.setHeader('Access-Control-Allow-Origin', 'http://myurl')
res.status(200);
res.send(true);
});
When I do the request I get the following error to the console:
OPTIONS http://myurl:15001/addItem 401(Unauthorized)
XMLHttpRequest cannot load http://myurl:15001/addItem. Response to
preflight doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://myurl' is therefore bot allowed access. The
response had HTTP status code 401.
When I try to do the same thing with my http get request everything works properly and I get the result.
I don't know why my OPTIONS request is unauthorized when I send 200 code for every OPTIONS request.
I tried to use cors node.js package but it didn't help, maybe I didn't used that right.
Could someone explain me how can I solve this and make my http post pass the preflight? Thanks a lot!
If you are using Angular 6, it supports proxy.conf which will proxy the Backend API URL. For more details, here is the link https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md

No 'Access-Control-Allow-Origin' is present, Origin 'null' not allowed access - Passport-SteamStrategy, Node

I have a site that is using Passport Steam Strategy. My server (Node with Express) is currently running on localhost:3000 while my front end is running on localhost:8080. I keep running into a cross-origin issue, only when attempting to authorize through Steam. My requests are made through Axios and I am using CORS. I've spent hours Googling and trying various things but I can't seem to get it to work.
This is the error that I get:
XMLHttpRequest cannot load
https://steamcommunity.com/openid/login?openid.mode=checkid_setup&openid.ns…3000%2Fsteam%2Fauth%2Freturn&openid.realm=http%3A%2F%2Flocalhost%3A3000%2F.
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.
Here is where the route is called from the front end:
linkSteam(){
api('http://localhost:3000/steam/auth')
.then(res => {
console.log(res);
state.user = res.data.user;
})
}
And here is my axios configuration on the front end.
let api = axios.create({
baseURL: 'http://localhost:3000/api/',
timeout: 3000,
withCredentials: true
})
My CORS is set up as follows
var whitelist = ['http://localhost:8080', 'https://steamcommunity.com', 'http://localhost:3000', 'null'];
// I added null here as someone said that it worked as their origin displayed null like mine does
var corsOptions = {
origin: function (origin, callback) {
var originIsWhitelisted = whitelist.indexOf(origin) !== -1;
callback(null, originIsWhitelisted);
},
credentials: true
};
I then import my CORS into my main file and use it as follows
app.use(cors(corsOptions))
app.use('*', cors(corsOptions))
I kept seeing that you can set your Access-Control-Allow-Credentials, etc and did so
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if ('OPTIONS' == req.method) {
res.send(200);
} else {
next();
}
});
This didn't help. I've tried breaking down my original function where /steam/auth is called and running a console.log(req.headers.origin) and spits back my correct URL, but then the error still reports that the Origin is null. If I set my Access-Control-Allow-Origin' to '*', I get a slightly different error that I must provide credentials, and that the Origin 'localhost:8080' is therefore not allowed.
Here's my /steam/auth route.
router.get('/steam/auth',
passport.authenticate('steam', {
failureRedirect: '/'
}),
function (req, res) {
res.redirect('/');
});
And this does work if I click on the URL that cannot be loaded and then login to Steam. It will then redirect me back to my site with my Steam profile information intact. The error is on attempting to get the initial redirect back to Steam in order to login. I have also tried doing this in a res.redirect to their direct URL and I get the same error.
Thanks in advance for any help! And let me know if I'm missing vital information. I've tried to include everything, but I wouldn't be surprise if I missed something.
If the error message in the question is the actual message the browser is reporting, it’s because your client-side code is trying to send a request to https://steamcommunity.com/openid/login.
So given that, no matter what config changes you make to your Node server on localhost:3000, that’s not going to change anything. Instead it seems like you you need to figure out where your client-side code is sending a request to https://steamcommunity.com/openid/login and why.
And the reason the request to https://steamcommunity.com/openid/login fails is that server doesn’t include the Access-Control-Allow-Origin response header in its response.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS has more details.
So because you can’t change the server’s behaviour, your browser will continue so block your code from getting at the response as long as it lacks the Access-Control-Allow-Origin header.
I don’t know how authorization is handled by Steam but maybe you instead need to either make the authorization request to Steam through your existing Node backend somehow, or else set up your own CORS proxy using, e.g., https://github.com/Rob--W/cors-anywhere/, and proxy your client-side authorization request to Steam through it.

AngularJS $resource makes HTTP OPTIONS request instead of HTTP POST for $save method

I'm in the process of writing a simple library application to get ready for a larger project with AngularJS. After reading a lot online about using $resource to interact with a RESTful API, I decided that it would probably offer some time-saving and scaling benefits to implement it instead of using $http for each request. The problem is that for some reason (I'm no expert on CORS and the request is being sent cross-domain) when using the $save method my Node.js console shows:
OPTIONS /books 200 1ms - 161b
Using the query() method works fine - the Node console shows:
GET /books 200 1ms - 228b
I've been stuck for several hours at this point, trying variations on the below but it always ends up being an OPTIONS request instead of POST (which is what it should be according to the Angular documentation) for the $save method.
AngularJS Web App
app.js
var libraryApp = angular.module('libraryApp', ['ngResource', 'ngRoute', 'libraryControllers']);
libraryApp.factory('$book', ['$resource', function ($resource) {
return $resource('http://mywebserver\\:1337/books/:bookId', { bookId: '#bookId' });
}]);
controllers.js
var libraryControllers = angular.module('libraryControllers', []);
libraryControllers.controller('BookCtrl', ['$scope', '$book', function($scope, $book) {
...
$scope.addBook = function () {
var b = new $book;
b.isbn = "TEST";
b.description = "TEST";
b.price = 9.99;
b.$save();
};
}]);
Node.js with Express REST API
app.js
var express = require('express'),
books = require('./routes/books'),
http = require('http'),
path = require('path');
var app = express();
...
// enable cross-domain scripting
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
// routing
app.get('/books', books.getAll);
app.get('/books/:isbn', books.get);
// This is what I want to fire with the $save method
app.post('/books', books.add);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
./routes/books.js
...
exports.add = function(req, res) {
console.log("POST request received...");
console.log(req.body.isbn);
};
Tried putting this line in my config function delete $httpProvider.defaults.headers.common["X-Requested-With"]; but no change.
I'm no Angular/Node pro but right now I'm thinking that it's something to do with it being cross domain and, like I said, I'm no expert on CORS.
Thanks in advance.
I know it may be in bad taste to answer my own question but I figured out the problem a few days after posting this.
It all comes down to how browsers manage CORS. When making a cross-domain request in JavaScript that is not "simple" (i.e. a GET request - which explains why the query() function worked), the browser will automatically make a HTTP OPTIONS request to the specified URL/URI, called a "pre-flight" request or "promise". As long as the remote source returns a HTTP status code of 200 and relevant details about what it will accept in the response headers, then the browser will go ahead with the original JavaScript call.
Here's a brief jQuery example:
function makeRequest() {
// browser makes HTTP OPTIONS request to www.myotherwebsite.com/api/test
// and if it receives a HTTP status code of 200 and relevant details about
// what it will accept in HTTP headers, then it will make this POST request...
$.post( "www.myotherwebsite.com/api/test", function(data) {
alert(data);
});
// ...if not then it won't - it's that simple.
}
All I had to do was add the details of what the server will accept in the response headers:
// apply this rule to all requests accessing any URL/URI
app.all('*', function(req, res, next) {
// add details of what is allowed in HTTP request headers to the response headers
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Credentials', false);
res.header('Access-Control-Max-Age', '86400');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
// the next() function continues execution and will move onto the requested URL/URI
next();
});
And then insert these few lines before the Express routing to simply return a HTTP 200 status code for every OPTIONS request:
// fulfils pre-flight/promise request
app.options('*', function(req, res) {
res.send(200);
});
Hopefully this will help anyone who stumbles on this page suffering from the same problem.
I didn´t actually try this, but wouldn´t it be enough to tell the Ressource how to handle the $save request?
$resource('http://mywebserver\\:1337/books/:bookId', { bookId: '#bookId' }, {save: {method: 'POST'});

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

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>
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.)
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']})
);
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:)');
});
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);
});
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();
});
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.
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
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.
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"]
}
});
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();
}
});
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
}));
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
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
/**
* 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.
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).
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.

Resources