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.
Related
I'm sending post request from "angular->port 4200" to "expressjs server->port 8000".
As an example i'm folowing this example: https://github.com/kuncevic/angular-httpclient-examples/blob/master/client/src/app/app.component.ts
I'm getting two error :
1)undefined from Nodejs(data and req.body.text)
2)Message received from background. Values reset
Angular side:
callServer() {
const culture = this.getLangCookie().split("-")[0];
const headers = new HttpHeaders()
headers.set('Authorization', 'my-auth-token')
headers.set('Content-Type', 'application/json');
this.http.post<string>(`http://127.0.0.1:8000/appculture`, culture, {
headers: headers
})
.subscribe(data => {
});
}
expressjs side:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
var path = require('path');
app.all("/*", 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');
next();
});
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.post('/appculture', function (req, res) {
var currentCulture = `${req.body.text} from Nodejs`;
req.body.text = `${req.body.text} from Nodejs`;
res.send(req.body)
})
app.listen(8000, () => {
console.log('server started');
})
Either you are not sending anything of there is no value in body.text
Try to console.log(req.body) instead of req.body.text.
Try to console.log(culture) and this.getLangCookie() on the client side to see if you are actually sending something.
You can also make use of the network tab in the browser to inspect the request that you are sending.
Angular side:
callServer() {
const culture = this.getLangCookie().split("-")[0];
const headers = new HttpHeaders()
headers.set('Authorization', 'my-auth-token')
headers.set('Content-Type', 'application/json');
this.http.get(`http://127.0.0.1:8000/appculture?c=` + culture, {
headers: headers
})
.subscribe(data => {
});
}
Nodejs side:
app.get('/appculture', function (req, res) {
currentCulture = req.query.c;
res.send(req.body)
})
I am trying to initiate a XMLHttprequest and hoping to receive response from express routes which are being placed in my app.js file but it is not working. Can anybody help what is going wrong
Below are my code in two diff files
File 1
function signup_data_validation() {
const data = {
fname: 'Nasir',
lname: 'Khatri'
};
const xhr = new XMLHttpRequest();
const url = '../app.js/customers';
const string_data = JSON.stringify(data);
xhr.responseType = 'json';
xhr.onreadystatechange = () => {
if(xhr.readyState === XMLHttpRequest.DONE) {
console.log(this.responseType);
}
}
xhr.open('POST', url);
xhr.send(string_data);
}
signup_data_validation();
File 2:
const express = require('express');
const sqlite3 = require('sqlite3');
const db = new sqlite3.Database('./miclothing');
const app = express();
app.use(express.static('public')); // web resources location
const PORT = process.env.PORT || 4001;
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");
next();
});
app.post('/app.js/customers', (req, res, next) => {
const query = req.query;
query = JSON.parse(query);
console.log(query.name);
console.log()
res.send("Done");
})
app.listen(PORT, () => {
console.log(`Sever is listening at ${PORT}`);
});
In File 1 change const url = '../app.js/customers' to the URL of your server.
const url = 'http://localhost:4001/app.js/customers'
You may change the port if the server is not listening on 4001
You are trying to assign to a constant(query = JSON.parse(query);), this will throw a type error.
You're checking req.query instead of req.body.
Also in your ajax request you set the responseType to JSON insted of the content type header as you're sending JSON but not receiving it.
I'm having a problem with my Firebase Functions https request.
This is my code to trigger it:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(function(req, res, next) {
res.setHeader('Content-Type', 'application/json');
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "GET, POST");
next();
});
app.use((err, req, res, next) => {
if (err instanceof SyntaxError) {
return res.status(400).send();
};
next();
});
app.post('/fetchPosts', (req, res) => {
exports.fetchPosts(req, res);
});
exports.widgets = functions.https.onRequest(app);
const cors = require('cors')({ origin: true })
exports.fetchPosts = (req, res) => {
console.log(req.body)
console.log(res)
let topics = req.body.topics || ['live'];
let start = req.body.start || 0;
let num = req.body.num || 10;
let next = start+num;
// setting up the response.
});
That looks good as far as I can tell..
Now when I do my api call I do:
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Content-Type', 'application/json; charset=UTF-8');
const request = new RequestOptions({ headers: headers });
const url = 'https://my-link.cloudfunctions.net/widgets/fetchPosts';
let payload = {
topics: ["live", "pets"]
}
console.log(JSON.stringify(payload))
this.http.post(url, JSON.stringify(payload), request)
.pipe(map((res:Response) => {
console.log(res.json())
}))
.subscribe(
data => console.log(data),
err => console.log(err),
() => console.log('Got feed')
);
and it just returns topics with just ['live'].. because of the failsafe that I set up on the backend.. but why isn't getting my topics that I'm sending?
Also, when I console.log(req.body) on the backend it just shows {}.. an empty object..
Any ideas why the req.body doesn't seem to work? I do it with start and num as well, but they all revert back to the failsafe.
You must use POST method to handle req.body . In your case, you can handle your variable with req.query
To handle req.body . You can use Postman, then select POST method and post data as JSON . You can read more to use Postman well.
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();
});
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())