I have written webservice using NodeJS and Express. Service is running on port 8090. Also I wrote frontend in AngularJS and running on port 8080.
Mongo has username and password stored of all users
When I login via HTML5/AngularJS frontend, the AngularJS app in turn calls the http post request of express. User is authenticated. And I set req.session.email = the email address of the user.
I even am able to return and check in console log of AngularJS that req.session.email was set correct in express
The problem is that I created an authentication function called "restrict" in Express to act as middleware function to give access to other get/post requests only if req.session.email is not undefined.
But even after session has been set, when this other get/post request of Express are calling by AngularJS app, this "restrict" function blocks the calls because it receives req.session.email as undefined
Both AngularJS and Express are on the same machine. But I don't think this is the problem.
Express Code Snippet
var url = 'mongodb://127.0.0.1:5555/contacts?maxPoolSize=2';
var mongojs = require('mongojs');
var db = mongojs(url,['data']);
var dbauth = mongojs(url,['users']);
// var request = require('request');
var http = require('http');
var express = require('express');
var cookieparser = require('cookie-parser');
var app = express();
var bodyParser = require('body-parser');
var session = require('express-session');
app.use(cookieparser());
app.use(session({secret:'v3ryc0mpl!c#t3dk3y', resave: false, saveUninitialized: true}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
var user_session;
app.all('*',function(req, res, next){
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
function restrict(req,res,next){
try{
if(req.session.email){
next();
}
else{
res.send('failed');
res.end();
}
}
catch(err){
res.send('failed');
res.end();
}
};
app.post('/login',function(req,res){
//removed DB function from here to make the code look simple
req.session.email = req.body.email;
req.session.password = req.body.password;
});
app.get('/loggedin',restrict,function(req,res){
res.send(true);
});
AngularJS Function that calls the Express function to check session status
var resolveFactory = function ($q, $http, $location,LoginDetails) {
var deferred = $q.defer();
$http.get("http://127.0.0.1:8090/loggedin")
.success(function (response) {
if(response == true){
deferred.resolve(true);
}
else
{
deferred.reject();
LoginDetails.setemail('');
LoginDetails.setpassword('');
$location.path("/");
}
})
.error(function (err) {
deferred.reject();
$location.path("/");
});
return deferred.promise;
};
Fundamentally the AngularJS Resolve Function that I created should be successful but it is not. It is failing. Am using live-server to run HTML/AngularJS on my laptop and nodemon to run Express app
Ok! So the reason is that AngularJS is running on a different port 8080
Express was running on port 8090. This means that if AngularJS calls an API of Express, the session of Express would be lost unless Express allows session to be passed on to AngularJS and AngularJS calls the API of Express with {withCredentials: true} parameter set. Below are the changes that I had to make to get the session maintained when AngularJS and ExpressJS were running on different ports
In AngularJS makes sure any API you call of Express, it should have
{withCredentials: true} like this
$http.get('http://expressdomainname:expressport/api',{withCredentials: true})
like wise in case you use $http.post
the parameter {withCredentials: true} is important
Now on the Express side
make sure you have app setting like this
app.all('*',function(req, res, next){
//Origin is the HTML/AngularJS domain from where the ExpressJS API would be called
res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
//make sure you set this parameter and make it true so that AngularJS and Express are able to exchange session values between each other
res.header("Access-Control-Allow-Credentials", "true");
next();
});
Please feel free to ask me question in case you have about this topic. I spent days to resolve this.
Related
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();
});
im having a little problem with my M.E.A.N(mongo, express, angular, node) application, when i do a GET request from my node server, it displays on 10 items instead of all 21 that are in the mongo db. i did some search on google and i read stuff saying it had to do with my CORS set up on my servers side, but i still cant seem to figure it out... here's my code:
index.js
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var _ = require('lodash');
var cors = require('cors');
// Create the application.
var app = express();
//enable the use of cors
app.use(cors());
// Add Middleware necessary for REST API's
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(methodOverride('X-HTTP-Method-Override'));
// CORS Support
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
app.models = require('./models/index');
// Load the routes.
var routes = require('./routes');
_.each(routes, function(controller, route) {
app.use(route, controller(app, route));
});
// Connect to MongoDB
var db = mongoose.connect('mongodb://localhost/isdbmeanapp');
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
mongoose.connection.once('open', function() {
// Load the models.
app.models = require('./models/index');
app.listen(3000);
console.log('Server running on localhost port 3000...');
});
i currently have 21 users(dummy data) in my database(mongodb) but when i run the above restangular query, it displays only 10 users. i also tried making requests with postman and thesame thing happens (with a 206 server status code).
im using restangular to make my requests:
Restangular.all('user').getList().then(function(user){
$scope.users = user;
});
please i need help in solving this problem... thanks in advance...
I'm as junior as it gets when it comes to web development so please bear with me on this. I'm attempting to access data from the USDA Food Composition Databases NDB API - https://ndb.nal.usda.gov/ndb/doc/index
via an angular $http request from localhost. I'm using an express server and gulp/browsersync and am encountering two errors:
Failed to load resource: http://api.nal.usda.gov/ndb/list?format=json&It=f&max=20&sort=n&offset=15&api_key=API_KEY the server responded with a status of
and
XMLHttpRequest cannot load http://api.nal.usda.gov/ndb/list?format=json&It=f&max=20&sort=n&offset=15&api_key=API_KEY. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 403.
I've tried setting my CORS headers in browsersync as well as my express server but I simply cannot get around this issue. Here is how I've configured the relevant code for this:
The $http request
(function() {
'use strict';
angular
.module('commonSenseDietApp')
.factory('getFoodNamesOnly', getFoodNamesOnly);
/** #ngInject */
function getFoodNamesOnly($log, $http, devEnvironment) {
var service = {
ndbApiKey: devEnvironment.api_key,
ndbApiUrl: devEnvironment.api_url,
getFoodNamesList: getFoodNamesList
};
return service;
function getFoodNamesList(limit) {
if(!limit) {
limit = 30;
}
// For a list of all request parameters visit - https://ndb.nal.usda.gov/ndb/doc/apilist/API-LIST.md
return $http.get(service.ndbApiUrl + '/ndb/list?format=json&It=f' + '&max=' + limit + '&sort=n&offset=15&api_key=' + service.ndbApiKey)
.then(returnFoodNamesList)
.catch(getFoodNamesFail);
function returnFoodNamesList(response) {
return response.data;
}
function getFoodNamesFail(err) {
// return $log.error(err.data);
return console.log(err);
}
}
}
})();
My Browersync/Express Server
'use strict';
var express = require('express');
var cors = require('cors');
var bodyParser = require('body-parser');
var http = require('http')
// require database data modeling via mongoose
var mongoose = require('mongoose');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var flash = require('connect-flash');
// Use express and set it up
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, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', false);
next();
});
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json())
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
var browserSyncSpa = require('browser-sync-spa');
var util = require('util');
var proxyMiddleware = require('http-proxy-middleware');
function browserSyncInit(baseDir, browser) {
browser = browser === undefined ? 'default' : browser;
var routes = null;
if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) {
routes = {
'/bower_components': 'bower_components'
};
}
var server = {
baseDir: baseDir,
routes: routes,
middleware: function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type');
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', false);
next();
}
};
browserSync.instance = browserSync.init({
startPath: '/',
cors: true,
browser: browser,
notify: true,
port: 8080,
server: server,
});
}
browserSync.use(browserSyncSpa({
selector: '[ng-app]'// Only needed for angular apps
}));
gulp.task('serve', ['setenvconstants','watch'], function () {
browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]);
});
gulp.task('serve:dist', ['setenvconstants','build'], function () {
browserSyncInit(conf.paths.dist);
});
gulp.task('serve:e2e', ['inject'], function () {
browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []);
});
gulp.task('serve:e2e-dist', ['build'], function () {
browserSyncInit(conf.paths.dist, []);
});
My Angular .config
(function() {
'use strict';
angular
.module('commonSenseDietApp')
.config(config);
/** #ngInject */
function config($logProvider, $httpProvider) {
// Enable log
$logProvider.debugEnabled(true);
// For Access-Control-Allow-Origin and Set-Cookie header
$httpProvider.defaults.withCredentials = false;
}
})();
I'm using gulp and browsersync to serve locally over localhost:8080 but no matter what I try (setting headers in express, setting headers in browsersync, setting browsersync cors option to 'true', setting browsersync https options to true, switching my 'Access-Control-Allow-Origin' to '*' or to "localhost:8080") none of it seems to work. I suspect the NDB API has forbidden my access but I can't get in contact with them to ask about it. Their suggested contact us link - "https://api.data.gov/contact/" leads to nothing.
Any suggestions or tips on this would be greatly appreciated. I'm a total noob here in terms of web development as well as posting to Stack Overflow so please let me know if my question doesn't make any sense and needs further clarification.
I was fortunate enough to stumble upon a solution although I don't quite understand what's happening and would certainly like to.
Turns out I was attempting to run a local server while using my VPN (https://www.privateinternetaccess.com/) which for some reasons was causing my CORS issue. Once I turned the VPN off and began using my local network I was able to run my server and make my requests without a hitch.
I'm not sure why using my VPN would cause a 403 but my guess would be that the API I was attempting to access simply does not allow request from a remote network like the one I was using. I will look into it more and update my answer shortly.
Try serving from https and not http when making your API calls. Being that you are fetching an https location, but issuing an http request, you will get CORS issue.
Look into: https://nodejs.org/api/https.html
Im new working with nodeJS. I have a webpage (with AngularJS) in a AWS ec2-server that gets information from a nodeJS(Express) server. Im trying to keep logged my users once they log in, even if they refresh. I have read that I can do that using express-sessions. This is my code in the client side:
$http({
method: 'GET',
url: 'http://ec2-bla-bla-bla.compute.amazonaws.com:8080/verifySession'
}).then(function successCallback(response) {
console.log(response);
}, function errorCallback(response) {
});
//And here i have the http post method that call login webservice
This is my server code:
var express = require('express');
var bodyParser = require('body-parser');
var path = require("path");
var session = require('express-session');
var app = express();
var loginManual = require('./model/ws_package/loginManual.js');
var sess;
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();
});
app.use(session({secret: 'ssshhhhh'}));
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.use(express.static(path.join(__dirname + '/view')));
app.get('/verify',function(req,res){
sess=req.session;
if(sess.email){
res.send({state:1,email: sess.email});
}
else{
res.send({state:-1,email: "NE"});
}
});
app.post("/login",function(req, res)
{
var userEmail; //here is myuseremail
//I have some login code here and if it is successful:
sess = req.session;
sess.email=userEmail;
res.send(response);
}
);
It is not working, but when I tested /login and /verify webservices, directly in my browser, writing the url, it works. Another thing I discovered is that everytime I make a new $http method from angular, my session id changes, so I dont know if that could mean something that affects me. How can I solve this? Sorry for my english, i am Costa Rican! Thanks!
I am creating an api (server side) based on Meanjs.org latest version (0.4.0) and i managed to pull off only the MEN part and create one in http://localhost:3000/api
as the frontend part i created an Angularjs in http://localhost:4000/
and then i run both application using (P)ackage (M)anager 2
I am trying to create a user by sending user credentials using $resource like this
angular.module('users').factory('AuthenticationResource', ['$resource',
function($resource) {
return $resource('http://localhost:3000/api/auth/signup', {}, {
post: {
method: 'POST'
}
});
}
]);
...
//In my controller
$scope.signup = function() {
AuthenticationResource.post($scope.credentials, function(response) {
$scope.authentication.user = response;
$state.go($state.previous.state.name || 'home', $state.previous.params);
});
};
While in my server side's express.js
'use strict';
var config = require('../config'),
express = require('express'),
...
cors = require('cors');
...
module.exports.initModulesServerRoutes = function(app) {
// Globbing routing files
config.files.server.routes.forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
};
module.exports.initCorsOption = function(app){
app.options('*', cors());
};
module.exports.init = function(db) {
// Initialize express app
var app = express();
...
// Initialise Cors options
this.initCorsOption(app);
// Initialize modules server routes
this.initModulesServerRoutes(app);
...
return app;
};
I am using node cors package to enable cors and just do app.options('*', cors()); to enable pre-flight across-the-board
But when i am trying to do a POST to http://localhost:3000/api/auth/signup i can see that my user is being saved to the database just fine but it doesn't give me any response and chrome console is giving me this
XMLHttpRequest cannot load http://localhost:3000/api/auth/signup. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4000' is therefore not allowed access.
What did i miss?
I think you are missing app.use before all your routes:
Only express:
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();
});
If you are using npm cors:
app.use(cors());