AngularJS POST request with JSON array data to Express server - angularjs

I have a static AngularJS website and an Express server running on different domains. The site sends GET requests to the server with a file name as the parameter. The server then requests the file from an S3 bucket, that sends it with "binary/octet-stream" as the "Content-Type". It decrypts the data and sends it back to the site with the same "Content-Type", which then downloads the file. This all works well for single file requests, however I would like to be able to send the server an array of file names all at once, and then be able to download multiple files. I tried sending the file names as a JSON array but I get the error:
XMLHttpRequest cannot load http://localhost:3000/decrypt. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'file://' is therefore not allowed access.
In my server console, the request shows up as OPTIONS instead of POST. I've also made sure to include Access-Control-Allow-Origin: * in my response headers. How should I go about resolving this?
UPDATE:
I was able to resolve the CORS error by adding the following middleware on my router:
function allowCrossDomain(req, res, next) {
if ('OPTIONS' == req.method) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
res.status(200).end();
}
else {
next();
}
}
However, I'm still not sure how to send multiple (for each file) "binary/octet-stream" in the response, and download them as files on the static site. Currently I am using angular-file-saver to save files from single requests.

You need to do a couple things in your server. First off are you using multer with bodyParser? Multer will allow you to add in post calls and will handle passing the data for you.
First AngularJS Post:
$http.post(baseUrl + "mypostmethod", o) //o is your object
.then(function successCallback(resp) {
console.log(resp)
}, function errorCallback(resp) {
console.log(resp)
});
Now as for your nodejs express setup, you want to ensure you are using all the proper modules. I will provide the basic list that I use in most of my projects. Also if you use req.headers.origin instead of * you sould no longer get the Access-Control-Allow-Origin error.
NodeJS:
var express = require('express'),
fs = require('fs'),
spdy = require('spdy'),
bodyParser = require('body-parser'),
multer = require('multer'),
helmet = require('helmet'),
upload = multer(), // this will allow you to pass your object into your post call with express
path = require('path'),
cookieParser = require('cookie-parser'),
request = require('request'),
app = express(),
http = require('http'),
formidable = require('formidable'); //Good for handling file uploads
app.use(helmet());
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH');
res.header('Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version');
next();
});
These are the basic ones I use in almost all my programs. The most important with expressis bodyParser and multer since these will allow you to use your gets and post properly.
Here is an example of a post NodeJS:
app.post('/mypostmethod', upload.array(), function(req, res) {
var body = req.body,
sess = req.session;
res.send({
Status: "Success"
});
});
In this post when you use upload.array() that is utilizing multer and now req.body is the object you passed in with your angular post call.
Let me know if you have any question, I hope this helps.

Related

To avoid the 'Access-Control-Allow-Origin' issue, how should CORS be set up on a MERN app that calls an API that is located somewhere else?

I am playing around with a MERN app that calls the themealdb api which works fine, until authentication and authorization with JWT and cookies are applied. If I log in, then whenever a call is made I get the following
Access to XMLHttpRequest at
'https://www.themealdb.com/api/json/v1/1/search.php?f=a' from origin
'http://localhost:3000' has been blocked by CORS policy: The value of
the 'Access-Control-Allow-Origin' header in the response must not be
the wildcard '*' when the request's credentials mode is 'include'. The
credentials mode of requests initiated by the XMLHttpRequest is
controlled by the withCredentials attribute.
It looks to me that the following line of code that is on the React side is to blame
axios.defaults.withCredentials = true;
If I comment this line out, the problem goes away and the calls are made without issue.
Looking around here through the answers it seems that the solution can be worked out on the backend which is Express for me, but so far nothing works.
The Express code had this for cors:
app.use(cors({origin: ['http://localhost:3000'], credentials: true}));
I replaced that with the following using both let and var for corsOptions in case but the same error:
let corsOptions = {
origin: 'http://localhost:3000',
credentials : true
}
app.use(cors(corsOptions));
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
Any advice on what to do? For such a situation what needs to be added to the server side to make it work?
Thanks
I usually use this snippet to enable CORS for a pre-configured list of origins:
const allowOrigins = ['http://localhost:3000', /** other domains if any */ ]
const corsOptions = {
credentials: true,
origin: function(origin, callback) {
if (allowOrigins.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
server.use(cors(corsOptions));
Also, as per MDN, you can try setting the withCredentials option to false on your client.
Alternatively, if you are connecting to a service which you do not maintain, you can instead create a Node proxy which will call the 3rd party service instead of your client calling it directly.
const express = require('express')
const request = require('request')
const port = process.env.PORT || 8000
let server = express()
const proxyMiddleware = (req, res, next) => {
let url = `https://www.example.com/${req.url}`
let proxyRequest = request(url)
// Pass request to proxied request url
req.pipe(proxyRequest)
// Respond to the original request with the response from proxyRequest
proxyRequest.pipe(res)
}
server.use(proxyMiddleware)
server.listen(port, () => console.log(`Listening on ${port}`))

Where should I write cors filter enabler code in angularjs

This is my js file, the following code is inside .controller
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200){
$http.post(smsHorizon,'Access-Control-Allow-Origin', '*').then(function(res){
res.addheader('Access-Control-Allow-Origin', '*');
res.addheader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.addheader('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if(res){
alert("OTP has been Send");
}
})
}
else{
}
}
Is this the way to code cors? Please help!!!
CORS request enabling always-on server side. You need to set CORS on response header.
CORS- How Internally Work
A resource makes a cross-origin HTTP request when it requests a resource from a domain or port which is different from the one which the first resource itself serves. For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts.
For example:
your app running on www.my-domain.com and its request for the resource on www.your-domain.com than browser do not allow to make the request within a script.
CORS- How To Resolve
suppose we made a request through angular script under domain www.my-domain.com is www.your-domain.com\id. This request hit on the server at endpoint /id on www.your-domain.com. So, at a time of rendering/sending a response by the server, it set 'Access-Control-Allow-Origin', '*' header in the response.
//java-jersey example
Response.status(200).entity(data)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET")
.build();
//Nodejs Example
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
For more details : https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

How to connect from angular to express server running on the same machine?

I am very new to express (and backend), and I am learning. So I mounted an express server on my machine by running express and npm install, and then overwriting the app.js with a simple code that serves something on /test
var express = require('express')
var app = express()
app.all('/*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type,X-Requested-With');
next();
});
app.get('/test', function (req, res) {
res.send('hi???');
});
app.listen(3100);
On my frontend, I am working with angular, it is running on localhost:3000, but when I run
function TestController ($http) {
var vm = this;
$http.get('http://localhost:3100/test')
.then(function (response) {
console.log(response);
});
}
It throws the following error:
XMLHttpRequest cannot load http://localhost:3100/test. Request header field Pragma is not allowed by Access-Control-Allow-Headers in preflight response.
I thought it could be a problem on the backend, but when I run
function TestController ($http) {
var vm = this;
var httpRequest = new XMLHttpRequest();
httpRequest.open('GET', 'http://localhost:3100/test', true);
httpRequest.send(null);
}
It won't throw any error, so I guess it is a problem with my angular configuration, but I cannot figure out where or what the problem is... how can I fix this? any help tweaking the backend or the frontend to fix this will be really helpful!
I already tried this, but it won't work, AngularJS POST Fails: Response for preflight has invalid HTTP status code 404 it doesn't makes any difference :(
Given the description of the problem, it was not about CORS, it had to do with headers not being handled correctly by the backend. Running the app on firefox, firebug suggests to add the token pragma to Access-Control-Allow-Headers... and then, another unkown header would jump up, now called cache-control so I only had to modify the app.js.
For anyone having this same problem, you just need to add the problematic headers to the string on 'Access-Control-Allow-Headers' :)
app.all('/*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers',
'Content-Type,X-Requested-With,cache-control,pragma'
+ otherHeadersSeparatedByComma);
next();
});

No 'Access-Control-Allow-Origin' header is present on the requested resource.

I've seen several questions and answers around this and mine is half working.
I have a node.js api server with url api.domain.com and the website on an nginx server at www.domain.com when I do the following in angular the request goes through on the api server, I see the request I see it getting parsed and put into the database. However, on the client side I do not get a return right away and then eventually I will see No 'Access-Control-Allow-Origin' header is present on the requested resource.
I know what is causing this behavior but shouldn't it throw the error before it hits the API server? Also note that the node.js server has cors enabled. The response that should be coming back is json.
$http({
method: 'POST',
url: "http://api.domain.com/addtrans/" + $scope.accountID,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT',
'Content-Type': 'application/x-www-form-urlencoded'
},
transformRequest: function (obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: {
payload: JSON.stringify(trans)
}
}).success(function (result) {
$scope.trans = {};
console.log(result);
});
I have used the below middleware for all of our projects and it has been proven to work best.
const allowCors = (req, res, next) => {
/** Allow all origins, for now TODO */
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Headers', 'Authorization, Content-Type');
res.header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE');
/** Browser check for pre-flight request to determine whether the server is webdav compatible */
if ('OPTIONS' == req.method) {
res.sendStatus(204);
}
else next();
};
// Put this code before the routes you want to allow CORS to
app.use(allowCors);
You should change the Allow-Origin to something more restricted for security reasons.
The above code covers CORS as well as pre-flight on most browsers(this ia major issue we were having in the beginning).
i used this a while ago (express 3.x):
// npm install --save cors
var express = require('express');
var cors = require('cors');
var app = express();
app.use(cors());
app.use(express.static());
app.get('*', function(){});
require('http').createServer(app).listen(3000)
Remember that the cors header should be on the response which is coming from server not the request which is sent from client.
You can use a middleware to enable cors on the server:
//CORS middleware
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'example.com');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}
//...
app.configure(function() {
...
app.use(allowCrossDomain);
...
});

Node Express Cross Origin for $http.get() calling

I did a simple node server , which I need it to be Cross Origin for $http.get() calling , so I add the required headers to the app.use as details in this answer. Finally the server code is -
var express = require('express');
var app = express();
var port = process.env.PORT || 3000;
app.use(express.static('.'));
app.all('/', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
app.listen(port);
console.log('server runs on port: ' + port);
In my index.html there is angular $http.get() calling to a another origin -
$http.get('http://itunes.apple.com/search', {
term: 'johnson'
});
but still this calling is denied by the browser and return error -
XMLHttpRequest cannot load https://itunes.apple.com/search. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
How could I make Cross Origin $http.get calling from the index.html correctly ?
You actually don't understand how cross-origin resource sharing works. Cross-origin requests should be allowed on server you making requests to, not on your server from which you are serving your page.
So, the answer is you can't make request to apple website if they haven't allowed you to do it.
P.S. You have allowed other websites to make request to your website by adding this code to your express app:
app.all('/', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();

Resources