Changing static content directory - angularjs

I am trying to set the express.static path to something different based on a session variable. The relevant code is below.
app.use( '/', function(req, res, next ) {
if ( req.session.loggedIn ) {
console.log("loggedIn : " + req.session.loggedIn);
app.use('/', express.static(__dirname + '/private'));
next();
}
else {
console.log("not logged in.");
app.use('/', express.static(__dirname + '/public'));
next();
}
});
When I start the application, I begin with not having req.session.loggedIn set. So it will use the static content in the /public directory (which contains an angular powered application for public users.) I then do a login (code below)
app.post('/login', function( req, res ) {
req.session.loggedIn = true;
var message = {};
message.success = true;
message.text = "Logging you in...";
res.json(message);
});
Which sets the req.session.loggedIn variable to be true. I then hit refresh on the page (and have tried hard refresh, and cache clear/refresh as well). The console.log tells me "loggedIn : true" as expected, however it does NOT load the static content from the /private directory. It instead continues to load from the /public directory.
Can anyone shed light on this issue?

The express.static is just another middleware so you can call it directly with the request and response parameters. Instead of adding it to the '/' route directly you could wrap it in another middleware like this:
var public_pages = express.static(__dirname + '/public');
var private_pages = express.static(__dirname + '/private');
app.use('/', function(req, res, next) {
if(req.session.loggedIn == 1) {
private_pages(req, res, next);
} else {
public_pages(req, res, next);
}
});

Related

Redirecting to static page when HTTP method is not found on Node backend

I have a single page app written in AngularJS and NodeJS. On the client side, there are several paths that the user can navigate to:
http://jabaridash.com/#!/home
http://jabaridash.com/#!/interests/travel
When the user types in a path that does not exist such as http://jabaridash.com/#!/foo, AngularJS handles it by rerouting to the /notFound path, and then that page redirects the user back to the home page. This is the code:
$urlRouterProvider.otherwise('/notFound');
This works when the path begins with #!/anyPath. However, if I were to type jabaridash.com/whatever, Angular does not reroute it. I am not sure if that has to do with the fact that I am using $stateProvider and modules to navigate, or I need to handle that type of path on the backend. I am assuming that I need to handle it on the Node side, because I do have one REST endpoint called photography setup on the NodeJS side, which can be accessed via jabaridash.com/photography (without #!). This endpoint works fine, but any other endpoint that I do not have setup will get a response of:
Cannot GET /something
This is to be expected, as there is no endpoint there. So essentially, how do i get NodeJS to redirect to my index.html. The way that I am serving the static page follows:
/**
* #description Set up the server
*
* #param dir directory to serve the index.html from
*/
function setupServer(dir) {
server.use(express.static(dir), function(req, res, next) {
// Allow cross origin from any host
res.setHeader('Access-Control-Allow-Origin', '*');
next();
});
// Set up the photography REST endpoint
photography_controller(server, dir);
}
My photography endpoint is setup as follows:
server.get('/photography', function(req, res) {
var searchPath = '/client/modules/interests/photography/img/thumbnail/';
// Send the list of files for use on client side
res.send(fileList(dir + searchPath, searchPath));
});
Is there a generic way to tell Node to say..."If the endpoint / HTTP method is not defined for a given path, redirect to a known path?"
This snippet below tells express to redirect to not-found when the path start with /example but has no specified handler in the router. Other routes that don't start with /example will not redirect because they won't be routed into the router in the first place.
const express = require('express');
const app = express();
// create a router for /example
var router = express.Router()
.get('/', function (req, res) {
res.send('example home');
})
.post('/about', function (req, res) {
res.send('About example');
})
/* catch all middleware for routes starting
with /example that redirects to /not-found */
.use(function (req, res, next) {
return res.redirect('/not-found');
});
// attach router
app.use('/example', router);
// create a not-found router handler
app.get('/not-found', function (req, res) {
res.send('Not found page');
});
app.listen(3000, () => console.log('App listening on port 3000'));
Right after your routes definition, do the following:
server.get('/photography', function(req, res) {
//do something
});
// catch 404 and forward to error handler
server.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
//
// error handler
server.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
//render the page you want to navigate to. In this example, I navigate the user to google
res.redirect('http://google.com');
});

On refreshing angularjs page gives error of page not found

I have an angular application in which when I used
$locationProvider.html5Mode(true);
for removing #! , it works good. but when I refreshes the page it gives error that
Get GET /c/electronic/computer/laptop not found which is my url
This is my app.js page
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var app = express();
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', true);
next();
});
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
This is my index page I putted all my functions and apis for firing queries where in models there had my mongodb's queries
var express = require('express');
var router = express.Router();
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
Category = require('./models/category');
Product = require('./models/product');
http = require('http');
mongoose.connect('mongodb://localhost/baazaronline');
var db = mongoose.connection;
router.get('/api/category', function(req, res){
Category.getCategory(function(err, category){
if(err){
throw err;
}
res.json(category);
});
});
router.get('/api/product', function(req, res){
Product.getProduct(function(err, product) {
if(err){
throw err
}
res.json(product);
})
});
router.get('/api/product/:_id', function(req, res){
Product.getProductById(req.params._id, function(err, product){
if(err){
throw err;
}
res.json(product);
});
});
Kasun, the reason that this is occurring is because you are trying to refresh the page from one of your sub routes (has nothing to do with ui-router).
Basically if you request www.yourdomain.com/ you likely have your server setup to return index.html which bootstraps your angular app. Once the app has loaded, any further url changes take html5Mode into consideration and update your page via ui-router.
When you reload your page the angular app is no longer valid as it has not loaded yet, so if you are trying to load a sub route (for example: www.yourdomain.com/someotherpage), then your server does not know how to deal with /someotherpage and likely returns 404 or some other error.
What you need to do is configure your server to return your angular app for all routes. I primarily use node/express, so I do something like:
app.get('*', function(req, res, next) {
// call all routes and return the index.html file here
}
Note: I usually use something like this as a final catch all, however I also include other routes above it for things like requesting static files, web crawlers, and any other specific routes that need to be handled.

Angular - Node - Possible to tell node which block from routes request from

Is it possible to tell a request to my Node App req in:
app.get('/*', function(req, res) {
res.sendFile(__dirname + '/site/index.html')
});
From which block of my Angular routes it is from (i.e. I want to be able to identify whats from the otherwise block);
.when('/user',
{...}
)
.when('/login',
{...}
)
.otherwise(
{...}
)
The reason I want it because I want to do something like:
app.get('/*', function(req, res) {
if (req is from otherwise block) {
res.status(400).sendFile(__dirname + '/site/index.html')
} else {
res.sendFile(__dirname + '/site/index.html')
}
});
The only thing i can otherwise think of is to create an array of all the allowed routes but I don't like duplication :p
Since the only link between Angular and Node is the HTTP request it's making, all you can do is retrieve the url and analyze which route it came from.
I'd define the routes you know about in Node, and then have a fallback for 404 errors:
app.get(['/login', '/user'], function(req, res) {
res.sendFile(__dirname + '/site/index.html')
});
app.get('*', function(req, res) {
res.status(404).sendFile(__dirname + '/site/404.html')
});

Angularjs CORS trouble with Node, Express, Oauth2, and Passport

Recently we have decided to switch our front-end from EJS to Angular separate the frontend and the backend completely. In doing so, we started to run into several issues across multiple browsers. On the back end we are using Node with express along with passport and oauth2. For the front end we are attempting to use angular. EJS works using express.render, but we would prefer to use angular directly by utilizing express as just a RESTful API.
I'm running both the backend and frontend locally at localhost:8080 and localhost:3000, respectfully. When just working with the backend (USING EJS, NOT ANGULAR), I can successfully go to our backend port in the browser, login via passport-oauth, and be redirect to the account page (from the providers login screen) where my json data is rendered via res.json. The problem is I am unable to do this from the frontend UI after removing EJS.
I've tried configuring CORS a dozen different ways while using three different browsers with no luck. The following three snippets are the errors I'm getting in the browsers console while trying to access localhost:8080 from the frontend via $http and $resource (see below for the code). The image below the three code snippets is what the node console is telling me when trying to access port 8080 from each different browser...
Chrome:
XMLHttpRequest cannot load 'PROVIDER-DETAILS-URL'. No 'Access-Control-Allow- Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
Firefox:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at 'PROVIDER-DETAILS-URL'. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at 'PROVIDER-DETAILS-URL'. (Reason: CORS request failed).
Safari:
XMLHttpRequest cannot load http://localhost:8080/auth/PROVIDER. Request header field Accept-Encoding is not allowed by Access-Control-Allow-Headers.
Console Image:
And the code:
Server:
app.js
'use strict';
const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const logger = require('morgan');
const errorHandler = require('errorhandler');
const path = require('path');
const flash = require('connect-flash');
const passport = require('passport');
const expressValidator = require('express-validator');
/**
* Load environment variables, where API keys and passwords are configured.
*/
const config = require('./config/config');
/**
* Route Handlers
*/
const index = require('./routes/index');
const account = require('./routes/account');
const logout = require('./routes/logout');
/**
* API keys and Passport configuration.
*/
const passportConfig = require('./strategy');
/**
* Create Express server.
*/
const app = express();
/**
* Express configuration.
*/
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
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, Authorization");
res.header("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT");
next();
});
app.use(cookieParser());
app.use(expressValidator());
app.use(session({
resave : true,
saveUninitialized : true,
secret : config.sessionSecret,
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
/**
* Primary app routes.
*/
app.get('/', index.execute);
app.get('/account', passportConfig.isAuthenticated, account);
app.get('/logout', logout.execute);
/**
* OAuth authorization routes.
*/
app.get('/auth/PROVIDER', passport.authenticate('PROVIDER'));
app.get('/auth/PROVIDER/callback', passport.authenticate('PROVIDER', { failureRedirect : '/'}), function(req, res) {
res.redirect('/account');
});
/**
* Error Handler.
*/
app.use(errorHandler());
/**
* Start Express server.
*/
app.listen(8080, () => {
console.log('App listening on port 8080');
});
module.exports = app;
strategy.js
'use strict';
const passport = require('passport');
const session = require('express-session');
const config = require('./config/config');
const OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
/**
* Put together the right header info for PROVIDER
*/
var authString = new Buffer(config.PROVIDER.clientID + ':' + config.PROVIDER.clientSecret);
var customHeader = {
"Authorization": "Basic " + authString.toString('base64')
};
/**
* OAuth2Strategy containing the customHeader created above.
*/
passport.use('PROVIDER', new OAuth2Strategy({
authorizationURL : config.PROVIDER.authorizationURL,
tokenURL : config.PROVIDER.tokenURL,
clientID : config.PROVIDER.clientID,
clientSecret : config.PROVIDER.clientSecret,
callbackURL : config.PROVIDER.callbackURL,
customHeaders : customHeader,
passReqToCallback : true
},
function( req, accessToken, refreshToken, profile, done ) {
req.session.accessToken = accessToken;
return done(null, profile);
}
));
passport.serializeUser(function(user, done) {
return done(null, user);
});
passport.deserializeUser(function(obj, done) {
return done(null, obj);
});
/**
* Login Required middleware.
*/
exports.isAuthenticated = function(req, res, next) {
if (req.isAuthenticated()) {
console.log('isAuthenticated');
return next();
}
res.redirect('/');
};
/**
* Authorization Required middleware.
*/
exports.isAuthorized = function(req, res, next) {
var provider = req.path.split('/').slice(-1)[0];
if (_.find(req.user.tokens, { kind: provider })) {
next();
} else {
res.redirect('/auth/' + provider);
}
};
index.js
exports.execute = function (req, res) {
if (req.user) {
console.log('========== ROUTES/INDEX.JS | 3 ==========');
res.redirect('/account');
} else {
console.log('========== ROUTES/INDEX.JS | 6 ==========');
res.redirect('/auth/PROVIDER');
}
};
Client:
I combined this to make it a little easier to read.
angular.module('StackOverflowPost', [])
.factory('APIService', function() {
function getData( $q, $http ) {
var defer = $q.defer();
$http.get( 'localhost:8080' )
.success( getDataComplete )
.catch( getDataFailed );
function getDataComplete( response ) {
console.log( response.Authorization );
defer.resolve(response.data.results );
}
function getDataFailed( error ) {
console.log( error.data );
defer.reject( 'XHR Failed for getData - ' + error.data );
}
return defer.promise;
}
})
.controller('MainCtrl', function( APIService ) {
var vm = this;
vm.getDataTest = function() {
APIService.getData().then(function( returnedData ) {
console.log( returnedData );
})
}
});
Any help or direction would be greatly appreciated.
UPDATE (4/28/2016): I updated the original post with more details. I also updated the code to what it is after another week of trial and error.
Please check this
https://gist.github.com/dirkk0/5967221
Code should be
// in AngularJS (client)
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
// in Express/nodeJS
// in NodeJS/Express (server)
app.all('/*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "GET, POST","PUT");
next();
});

Unable to hit my local API route in Express

I have a server and client folder, inside my client folder I have 2 Angular apps /website and /dashboard
My current routing setup (just for development) going to / will load the website app and views and /dashboard loads the dashboard up:
//website api ==================================================================
var website = express.Router();
app.use('/', website);
app.use('/', express.static("../client/"));
console.log(__dirname + "../client/");
website.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
website.get('/', function(req, res) {
var path = 'index.html';
res.sendfile(path, { 'root': '../client/website/' });
});
//dashboard api ================================================================
var dashboard = express.Router();
app.use('/dashboard', dashboard);
dashboard.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
dashboard.get('/dashboard', function(req, res) {
var path = 'index.html';
res.sendfile(path, { 'root': '../client/dashboard/' });
});
// API to add new accounts:
app.post('/api/accounts/', accountsController.create);
In my dashboard app, the accounts controller I have the following $resource call:
var Account = $resource('/api/accounts');
Which is suppose to hit this API on my server main.js:
// API to add new accounts:
app.post('/api/accounts/', accountsController.create);
However currently getting a 404 on the call
'POST http://localhost:9999/api/accounts 404 (Not Found)'
I think it's the mismatch of trailing slash vs. no trailing slash between your angularjs code and your expressjs code. Try app.post('/api/accounts', accountsController.create);.

Resources