Cors error in Node - node.js

I am using Node as my server and angular as my front end service.
I have installed cors from npm. Even after using the CORS headers still I am getting the same error. Is it because my function is not bounded my app.get().
How can I implement in my case ?
// ## =======BASE SETUP======= ##
const arangojs = require('arangojs');
const express = require('express');
const aqlQuery = arangojs.aqlQuery;
const bodyParser = require('body-parser');
// ## Const variables for connecting to ArangoDB database
const dbConfig = {
host: '0.0.0.0',
port: '8529',
username: 'xyz',
password: 'xxyz',
database: 'sgcdm2',
};
// ## Connection to ArangoDB
const db = new arangojs.Database({
url: `http://${dbConfig.host}:${dbConfig.port}`,
databaseName: dbConfig.database
});
db.useBasicAuth(dbConfig.username, dbConfig.password);
var soap = require('strong-soap').soap;
var http = require('http');
var fs = require('fs');
//CORS PLUGIN
var cors = require('cors');
var app = express();
app.use(cors());
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
var test = {};
test.server = null;
test.service = {
CheckUserName_Service: {
CheckUserName_Port: {
//first Query function
checkUserName: function(args, callback, soapHeader, req, res) {
//CORS PLUGIN
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.setHeader('Access-Control-Allow-Credentials', true);
console.log('checkUserName: Entering function..');
db.query(aqlQuery `
LET startVertex = (FOR doc IN spec
FILTER doc.serial_no == '"123456abcde"'
LIMIT 2
RETURN doc
)[0]
FOR v IN 1 ANY startVertex belongs_to
RETURN v.ip`, {
bindVar1: 'value',
bindVar2: 'value',
}).then(function(response) {
console.log("response is " + JSON.stringify(response._result));
callback(({
status: JSON.stringify(response._result)
}));
});
var wsdl = require('fs').readFileSync('check_username.wsdl', 'utf8');
fs.readFile('./check_username.wsdl', 'utf8', function(err, data) {
test.wsdl = data;
test.server = http.createServer(function(req, res) {
res.statusCode = 404;
res.end();
});
test.server.listen(8000, null, null, function() {
test.soapServer = soap.listen(test.server, '/test/server2.js', test.service, test.wsdl);
test.baseUrl = 'http://' + test.server.address().address + ":" + test.server.address().port;
});
console.log('server listening !!!');
});
If I use cors plugin in chrome, the function works fine without any trouble but I would like to find a solution in a proper way. I have also discussed this problem a while ago Node.js CORS error

The browser sends the HTTP OPTIONS preflight request first and the SOAP server doesn't handle it well obviously because it returns an error response.
If the strong-soap doesn't have any support for CORS you could try putting an nginx proxy in front of the SOAP server which would response the CORS preflight requests.

Do:
npm install cors --save
Add:
const cors = require('cors')
app.use(cors())

Related

Node js CORS failure

I have been trying to build a web application using NODE and React without Express router but I am getting a lot of issues with the CORS part since both node and react are running on different ports. I don't want to use express in this case since i want to use native http module provided by node, hence I am unable to use CORS middleware which is in the npm library.
I have tried every possible solution which would work for resolving the CORS issue but I am at a dead end now. I have shared my server side code below.
/*
* Main server file
*/
//Depenedencies
let https = require('https');
let url = require('url');
let fs = require('fs');
let handlers = require('./lib/handlers');
let stringDecoder = require('string_decoder').StringDecoder;
let decoder = new stringDecoder('utf-8');
//server object definition
let server = {};
//https certifications
server.certParams = {
'key': fs.readFileSync('../lib/Certificates/serverKey.key'),
'cert': fs.readFileSync('../lib/Certificates/serverCert.crt')
};
server.https = https.createServer(server.certParams, (req, res) => {
server.unifiedServer(req, res);
});
//main server
server.unifiedServer = (req, res) => {
//converting url to url object
let parsedUrl = url.parse("https://" + req.rawHeaders[1] + req.url, true);
//constructing required params for handlers
let method = req.method;
let route = parsedUrl.pathname;
let queryStringObject = parsedUrl.query;
let headers = req.headers;
//function specific params
let requestBodyString = "";
let chosenHandler;
let requestObject = {};
let responsePayload = {
'Payload': {},
'Status': ""
};
//streaming in the req body in case of post req
req.on("data", function(chunk) {
requestBodyString += chunk;
});
//this is called regardless of the method of the req
req.on("end", function() {
//this is specific to post req
requestBodyString += decoder.end();
requestBodyString = method == "POST" ? JSON.parse(requestBodyString) : {};
//the request object sent to the handlers
requestObject.method = method;
requestObject.reqBody = requestBodyString;
requestObject.queryObject = queryStringObject;
chosenHandler = server.handlers[route] ? server.handlers[route] : server.handlers.notFound;
let headers = {
"Access-Control-Allow-Origin" : "https://localhost:3000/",
"Access-Control-Allow-Methods" : "OPTIONS, POST, GET",
"Access-Control-Allow-Headers" : "Origin, Content-Type"
};
chosenHandler(requestObject)
.then((result) => {
//post handler call
responsePayload.Status = "SUCCESS";
responsePayload.Payload = result;
//send the data back
res.writeHead(200,headers);
res.write(JSON.stringify(responsePayload));
res.end();
}).catch((error) => {
//error handler
responsePayload.Status = "ERROR-->" + error;
//send the data back
res.writeHead(200,headers);
res.write(JSON.stringify(responsePayload));
res.end();
});
});
};
//router definition
server.handlers = {
'/login': handlers.login,
'/signup': handlers.signup,
'/checkUserName': handlers.checkUserName,
'/checkEmail': handlers.checkEmail,
'/notFound': handlers.notFound
};
//init function
server.init = () => {
//start the https server
//TODO--> Change this to handle changing port and env
server.https.listen(5000, function() {
console.log('The https server is listening on port 5000 in Development mode');
});
};
//export the module
module.exports = server;
I am making a post request to test the connection but I am getting this evertime:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:5000/login. (Reason: CORS request did not succeed).
Can anyone please tell me what am I doing wrong?
Set the "Access-Control-Allow-Origin" header in the response stream object.
Try with the below snippet -
server = http.createServer(function(req,res){
// Set CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Request-Method', '*');
res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
res.setHeader('Access-Control-Allow-Headers', '*');
if ( req.method === 'OPTIONS' ) {
res.writeHead(200);
res.end();
return;
}
// ...
});
OR it that does not work, try using -
res.setHeader('Access-Control-Allow-Headers', req.header.origin);
Use this middle ware after let decoder = new stringDecoder('utf-8');
var express = require('express');
var app = express();
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');
res.header('Access-Control-Allow-Credentials', 'true');
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.status(200).send();
} else {
next();
}
};
app.use(allowCrossDomain);
This is relevent for express framework.

Angular to Node + Express.js http.post() stalled: status 204 no content. Suspected CORS Preflight OPTIONS

I'm using client side ionic with server side node.js + express.js. Currently testing in my local computer.
I am able to do a POST request through postman, however I couldn't make it through ionic.
Research
I have spent almost 1 day to investigate this. But I couldn't find a way to solve this. More over, there is no error on the client nor the server side, thus it is difficult for me to investigate this.
From what I can see, I suspect the error comes from the PREFLIGHT OPTIONS settings. I should set it somewhere in my node + express.
I am using the cors plugin https://www.npmjs.com/package/cors and use the settings to allow PREFLIGHT OPTIONS, however it still does not work.
I looked at the chrome network inspection, this is what I have:
And this is what it looks in the console.
My Client-side Code (Ionic)
postAPI() {
return new Promise ((resolve,reject)=>{
this.http.post("http://localhost:8080/api/status/", {
"body" : "This is the body post"
}, httpOptions).subscribe((val) => {
console.log("POST call successful value returned in body", val);
resolve();
}, error => {
console.log("POST call in error", error);
reject();
}, () => {
console.log("The POST observable is now completed.");
})
})
}
My Server-side Code (Node + Express)
Here, I am using CORS OPTIONS settings to allow all OPTIONS requests.
I am setting it in server.js while the route itself is in status.js.
server.js
const express = require('express'); // call express
const app = express(); // define our app using express
var cors = require('cors'); // setup CORS so can be called by ionic local app
const port = process.env.PORT || 8080; // set our port
// ALLOW CORS
app.use(cors());
// SET CORS for PREFLIGHT OPTIONS
app.options('*', cors());
// Libraries
const bodyParser = require('body-parser');
const admin = require('firebase-admin');
const serviceAccount = require('./serviceAccountKey.json');
// Json
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Firebase Configs
//firebase admin sdk for Firestore
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://menuu-sm-dev.firebaseio.com"
});
var afs = admin.firestore();
var db = afs;
app.set("afs", afs);
var db = admin.firestore();
const settings = {timestampsInSnapshots: true};
db.settings(settings);
app.set("db", db);
// ROUTES
app.use('/api',require('./routers/api/api'));
app.use('/',require('./routers/home'));
// START
app.listen(port);
console.log('Server is served on port ' + port);
api.js
// SETUP
const express = require('express'),
router = express.Router();
const url = require("url");
const path = require("path");
///const sanitizer = require("sanitize")();
// ROUTES (/api/)
router.use('/user',require('./user'));
router.use('/status',require('./status'));
router.use('/timeline',require('./timeline'));
router.use('/photo',require('./photo'));
router.use('/like',require('./like'));
router.use('/comment',require('./comment'));
router.use('/checkin',require('./checkin'));
router.use('/promotion',require('./promotion'));
// OTHERS
module.exports = router;
status.js
// SETUP
const express = require('express'),
router = express.Router();
const url = require("url");
const path = require("path");
const Timeline = require("../../models/Timeline");
const Post = require("../../models/Post");
///const sanitizer = require("sanitize")();
// ROUTES
// ===============================================================
// /status/
var statusRoute = router.route('');
// Create
statusRoute.post((req, res) => {
let query = url.parse(req.url,true).query;
let userKey = query.userkey;
let statusKey = query.statuskey; // ga dipake
let reqBody = req.body;
let db = req.app.get('db');
// ! remember to do sanitizing here later on
if (typeof userKey != 'undefined'){
// Create New Status
let newStatusRef = db.collection('status/'+userKey+'/status').doc();
newStatusRef.set(reqBody);
// Fan-Out
let docId = newStatusRef.id; // get pushed id
//let docId = "1";
// Insert request body to models
var post = new Post();
var timeline = new Timeline();
Object.entries(reqBody).forEach( ([key, value]) => {
timeline.set(key,value);
post.set(key,value);
}
);
// Specify operations to be done
var batch = db.batch();
let newPostRef = db.collection('posts/'+userKey+'/posts').doc(docId);
batch.set(newPostRef, post.data);
console.log("b" + batch);
// Timeline & Commit
getFollowers(userKey, db)
.catch((error) => {
console.error("Error writing document: ", error)
})
.then((followers) => {
// ATTENTION!!
// if followers > 9, batch write supposedly wont work because max limit of batch write is 10
if (followers.length!=0){
followers.forEach((f) => {
let newTimelineRef = db.collection('timeline/'+String(f)+'/timeline').doc(docId);
console.log(typeof batch);
console.log("a" + batch);
batch.set(newTimelineRef, timeline.data);
});
}
// Commit changes
batch.commit()
.then(() => {
console.log("POST Request");
res.json({"Action":"CREATE","Status":"Successful", "User key":userKey, "Post Key": docId, "followers":followers});
})
.catch((error) => {
console.error("Error writing document: ", error)
})
});
}
});
Could you help me find the cause of this issue. Thanks!
Replace app.use('cors') with the below code:
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", '*');
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
return res.status(200).json({});
}
next();
});

CORS issues even after using npm cors plugin in node server

I have created a simple server in node js to take the request from a react app.
But for the GET method there is no CORS error but whenever I do post, it gives me an error.
For the POST method to work, I have implemented in index.js file of the actions folder and it should hit the url from the server.js file.
index.js
import axios from 'axios';
export const GET_NAVBAR = "GET_NAVBAR";
export const LOGIN = "LOGIN";
export const BASE_API_URL = "http://localhost:3030";
export const GUEST_API_URL = "https://XXX.XXX.XXX.X:5443/wcs/resources/store/1";
export const getNavbar = () => {
return axios.get(BASE_API_URL + '/topCategory').then(res => {
return {
type: GET_NAVBAR,
payload: res.data.express.catalogGroupView
};
});
};
export const login = () => {
return axios.post(GUEST_API_URL + '/guestidentity', {}).then(res => {
console.log(res);
return {
type: LOGIN,
payload: {}
}
}).catch(e => {
console.log(e);
return {
type: LOGIN,
payload: {}
}
});
};
server.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const Client = require('node-rest-client').Client;//import it here
const app = express();
const helmet = require('helmet');
const morgan = require('morgan');
// enhance your app security with Helmet
app.use(helmet());
// use bodyParser to parse application/json content-type
app.use(bodyParser.json());
app.use(cors());
// log HTTP requests
app.use(morgan('combined'));
app.post('/guestidentity', (req, res) => {
var client = new Client();
// direct way
client.post("https://XXX.XXX.XXX.X:5443/wcs/resources/store/1/guestidentity", (data, response) => {
res.send({express: data});
});
});
const port = 3030;
app.listen(port, () => console.log(`Server running on port ${port}`));
I don't know where my code is getting wrong. Can anybody please help me to troubleshoot this issue. I would be grateful if someone could provide an insight or guide me a little. Thanks
For my part I used
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
It will accept from any * sources, you might want to change that later
In your server.js , add the following middleware.
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:3030/');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
};
app.use(allowCrossDomain);

How to get a PUT route to work correctly (and not return 404 error) with Axios and Express?

I have an app that makes this call:
handleUpdate (id, data) {
const url = "/sites/" + id;
axios.put(url, data)
.then(res => {
// handling of response
})
.catch(console.error);
}
The route in the server.js file is:
router.route('/sites/:site_id')
.put(function(req, res) {
// handling of update
})
However, every time I make the handleUpdate call, I receive this message:
xhr.js:178 PUT http://localhost:3000/sites/5a39783d09ba9fec39b34d37 404 (Not Found)
The id is correct, but I'm clearly not doing something right.
Below is the applicable portion of the server.js:
//server.js
'use strict'
//first we import our dependencies...
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
//and create our instances
var app = express();
var router = express.Router();
//set our port to either a predetermined port number if you have set
it up, or 3001
var port = process.env.API_PORT || 3001;
//db config
var mongoDB = // my mlab database connection info;
mongoose.connect(mongoDB, { useMongoClient: true })
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
//now we should configure the API to use bodyParser and look for JSON
data in the request body
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//To prevent errors from Cross Origin Resource Sharing, we will set our
headers to allow CORS with middleware like so:
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods',
'GET,HEAD,OPTIONS,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-
Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-
Request-Method, Access-Control-Request-Headers');
//and remove cacheing so we get the most recent comments
res.setHeader('Cache-Control', 'no-cache');
next();
});
//now we can set the route path & initialize the API
router.get('/', function(req, res) {
res.json({ message: 'API Initialized!'});
});
You need to use method-override package in order to handle the put request:
1- install method-override package
npm install method-override --save
2- use it in your app
var express = require('express')
var methodOverride = require('method-override')
var app = express()
// override with the X-HTTP-Method-Override header in the request
app.use(methodOverride('X-HTTP-Method-Override'))
3- catch put request
router.route('/sites/:site_id').put(function(req, res) {
// handling of update
})
4- ajax
var config = {
headers: {
'X-HTTP-Method-Override', 'PUT'
}
}
axios.post(url, data, config)
.then(res => {
// handling of response
})
.catch(console.error);
I realized at long last that I was directing the PUT request to the main app and not to the api. Once I corrected for this, it worked perfectly.
How obvious errors seem once they've been solved.
Thanks to everyone who helped out.

Node.js + express + cors not working: pending options requests

I tried about 10 different options but I cant get my POST request start working instead i have options request that is pending and never completes
server.js
var express = require('express');
var path = require('path');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var cors = require('cors');
var app = express();
app.use(cors());
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, Accept');
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.send(200);
} else {
next();
}
};
app.use(allowCrossDomain);
app.options('*', cors());
app.use(require('./routes/order-templates.js'));
app.use(require('./routes/statuses.js'));
app.use(require('./routes/fields.js'));
app.use(require('./routes/users.js'));
app.use(require('./routes/groups.js'));
app.use(require('./routes/upload.js'));
app.use(require('./routes/feedback.js'));
app.use(require('./routes/order.js'));
app.use(express.static('public'));
var mongoDB = 'mongodb://localhost/ior';
mongoose.connect(mongoDB, {
useMongoClient: true
});
app.get('*', function (request, response) {
response.sendFile(path.resolve(__dirname, 'public', 'index.html'))
})
app.listen(3000, function () {
console.log('Fired at ' + Date());
});
users.js
var express = require('express');
var router = express.Router();
var User = require('../model/user.js');
var bodyParser = require('body-parser');
var app = express();
var cors = require('cors')
var corsOptions = {
origin: 'http://188.225.82.166:3000/',
optionsSuccessStatus: 200
}
app.use(cors())
app.use(bodyParser.json());
app.options('/users/auth/', cors(corsOptions))
app.post('/users/auth/', cors(), function (req, res, next) {
User.findOne({"mail": req.body.mail, "password": req.body.password}, function (err, user) {
if (err) throw err;
if (user == undefined) {
res.send({"result": "error" })
res.sendStatus(200)
} else {
res.send({"result": "ok", "_id": user._id, "type": user.type })
}
});
})
module.exports = app
If I do
app.use(cors());
app.use(function(req, res, next) {
console.log('After CORS ' + req.method + ' ' + req.url);
next();
});
in server.js I get
After CORS GET /
After CORS GET /bundle.js
After CORS GET /bootstrap.css.map
After CORS GET /favicon.ico
And nothing prints in console after post requests is triggered.
Also worth mentioning the fact, that the problem exists only when I deploy to server with ubuntu. Locally on mac os machine everything is fine
You should use cors before bodyParser and allow it for PUT/DELETE also.
// Add cors
app.use(cors());
app.options('*', cors()); // enable pre-flight
app.use(bodyParser.json());
It may be helpful for others like me:
In the beginning I thougth it is the server side problem, but then the reason of cors error became my frontend. I was sending requests to localhost:3000/api instead of http://localhost:3000/api
That's it
For others like me scratching head for 2hrs trying to fix the POST cors issue, please also double check the options of your POST request.
For me it was a small typo of header: {...} instead of header(s): {...} in the POST options, the express server configured using cors allowing all origins responded with "Access-Control-Allow-Origin" restricted error.
Try this. In you user.js file use router.post instead of app.post.
router.post('/users/auth/', cors(), function (req, res, next) {
User.findOne({"mail": req.body.mail, "password": req.body.password}, function (err, user) {
if (err) throw err;
if (user == undefined) {
res.send({"result": "error" })
res.sendStatus(200)
} else {
res.send({"result": "ok", "_id": user._id, "type": user.type })
}
});
})
Then export router module
module.exports = router;
Also i would suggest to use bodyparser in server.js file. So you don't need to use it in every file.
After applying "cors" middleware. You should append "http://" before "localhost:". in URL
axios.get("http://localhost:8080/api/getData")
.then(function (response) {
this.items= response.data;
}).catch(function (error) {
console.log(error)
});
Get rid of the trailing slash in origin.

Resources