nodejs express static routes creating multiple sessions - node.js

I am using Nodejs and Express. I have a routes.js file defining all my routes. When I try to use req.session.regenerate(), express creates multiple sessions including one each for static file requests as well.
Whats confusing is req.session.regenerate() is within app.get('/' route and it seems from the console.log it gets called only once. But somehow when I look at the mongodb session collection, there are multiple sessions created for one page request.
basically what I am trying to do is when the login page is requested I want to create a new session so that express does not re-use previous session's cookie.
Any pointers?
routes.js
exports = module.exports = function(app, passport) {
//When I uncomment this line, it shows me the number of times a request is made.
//app.all('*', function(req, res, next){console.log('Request made to server'); next();});
app.get('/', function(req, res){
if (req.isAuthenticated()){
res.redirect('./home');
}else{
req.session.regenerate(function(err) {
console.log('Regenerated');
})
res.render('./login')
}
});

Put your express session middleware after your express.static() middleware.

Related

Express routes invoking multiple router function

I've created a NodeJS Express app. But my express route is invocking multiple routes function, one after another, but I only need one at a time.
My express app.js
app.use(routes)
Express router:
const router = express.Router();
router.post("/product", controller.productFunction)
router.post("/user", controller.userFunction)
router.get("/:id", idController.getId)
Whenever I create a post request for "/product" route, first the productFunction is invocked, but then the "/:id" routes getId function is also get invocked. Same thing happen for /user route as well. Always /:id route is getting invocked.
Is there any way to prevent this?
I even tried this way, but after the homepage loading then again it invockes getId function.
app.get("/", (req, res, next) => {
res.sendFile(..........);
});
app.use(routes);
I am sure that this is not an issue with the router itself.
You can't skip from POST to GET handling. So invocations are caused by different requests.
router.get("/:id", idController.getId) kind of wild card, and <server_url>/favicon.ico will trigger it
If you check it via browser it tries to get favicon or smth else and invokes this handler.
Try to make POST request via curl/Postman and idController.getId should not be called.
It is risky to serve static and process requests on a same level.
You can add some prefix to all your request, like that app.use('/api', routes); then static file will be available on /<file_name> and all server logic will be under /api/<request>

node JS express framework sendFile("home.html",{context?})

I'm reading the Express framework docs, making my basic login/redirect page routes.
The following route accepts the submission:
app.post('/',function(req,res){
//console.log("USERNAME: "+req.body.username);
//console.log("PASSWORD: "+req.body.password);
res.redirect('/chat');
});
and this:
app.get('/chat', function(req, res){
res.sendFile(__dirname + '/templates/chat.html');
//console.log("request");
});
takes the user to a new page.
How do I send context? Should I be using res.render()? Neither function seems to contain an option for data like {username:req.body.username}. How should data be passed between routes?
Generally to handle logins with express you'd use something like passport's local strategy, which attaches a user object to the request object (req.user) for you for each route. I don't know that what you're trying will work in a larger context -- you'd need some kind of session-based middleware like express-session at the very least, so you can attach variables per session (I think it gives you req.session). By default, express has the capability to store information for one request/response cycle (res.locals) or for the entire instance of the app (i.e. for all users) (app.locals).
As far as getting data into views, you would use res.render with something like EJS, pug, or another view engine. For example, if in your route, you had something like:
route.get('/', (req, res) => {
res.render('template', { username: 'yourname' })
}
you can refer to that in your ejs template like so:
<h1>Hello, <%= username %>!</h1>
which will get sent back as this:
<h1>Hello, yourname!</h1>
So, to answer your question:
You would use res.render to get variables & data into your views
You don't share data across routes by default except app-level data that applies to all users, which can be set on app.locals
You can use authentication middleware like passport and session middleware like express-session to keep track of user information across routes per session.
Hope this helps! Good luck with express!

Stop duplication of passportjs isAuthenticated code in Express route files

I am using passportjs for my authentication.
I have lots of different routes throughout the project, 95% of them require the following function:
// Middleware functions
function isAuthenticated(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/login');
}
At the moment, I am putting this function at the bottom of EVERY route file.
Is there a way to write it once, and be able to use it in all the route files?
If you add that middleware before the routes that require it, all requests will pass through it before they get forwarded to the correct route handler:
// doesn't require an authenticated request
app.use(router1);
// add the middleware just once
app.use(isAuthenticated);
// all following route(r)s require an authenticated request
app.use(router2);
app.use(router3);
...

Node.js middleware or not

I'm new to Node.js and I'm migrating a simple site of mine to Node.js mostly as a learning experience.
In all my sites, I like to keep the most relevant information on the site in a "sitemeta" object. This is queried from Redis on each request and if that fails (which it only does if sitemeta gets updated and then it reads it from MySQL instead and saves it in redis so that next request again gets it from redis as redis is much speedier than MySQL).
So, in PHP I would simply add the call for sitemeta in a settings.php file that I always include on top of each file so that the information like home_url or site_mode (that are part of sitemeta object) is always there.
However, now in Node.js I was wondering if this is really the way to go or if there's a better way to actually have this happen as a middleware rather than making like so, at the top of every controller file (router files, really).
//in index.js
var express = require('express');
var router = express.Router();
var site = require('./../lib/sitemeta');
...
//using it for something.
var siteMeta = site.meta();
res.render('index', { title: siteMeta.title });
Or, could I even have the sitemeta instantiated in app.js so that it's queried only once (when the node app.js starts) unless it needs to be updated and if so a refresh can be provoked somehow?
Thanks.
I think the best approach is through a middleware. Wherever you store you metadata (memory, redis, etc), having a middleware will let you inject you siteMeta in all requests, with the capacity to adapt your siteMeta based on the received request (locale, etc). We usually use a lot of small, easily testable middleware functions to inject different data elements for another middleware down the pipeline to process and produce the response.
// with promises
app.use(function(req, res, next){
req.siteMeta = loadSiteMeta();
next();
});
app.get('/endpoint', function(req, res){
// wait for the promise to be fulfilled
req.siteMeta.then(function(siteMeta){
res.render('my-view', { title: siteMeta.title });
});
});
// without promises
app.use(function(req, res, next){
loadSiteMeta(function(err, siteMeta){
req.siteMeta = siteMeta;
next();
});
});
app.get('/endpoint', function(req, res) {
// siteMeta will be populated
res.render('my-view', { title: req.siteMeta.title });
});
The actual implementation of loadSiteMeta will depend on your selected storage. The benefits of using promises instead of classic callbacks here is that, if you have multiple middleware loading different data elements before reaching your final processing function, they will be performed in parallel instead of sequentially. You might want to use Promise.all() to wait for all promises you need in your final function.

How to use AngularJS routes with Express (Node.js) when a new page is requested?

I'm using Express, which loads AngularJS from a static directory. Normally, I will request http://localhost/, in which Express serves me my index.html and all of the correct Angular files, etc. In my Angular app, I have these routes setup, which replace the content in an ng-view:
$routeProvider.when('/', {
templateUrl: '/partials/main.html',
controller: MainCtrl,
});
$routeProvider.when('/project/:projectId', {
templateUrl: '/partials/project.html',
controller: ProjectCtrl,
});
$locationProvider.html5Mode(true);
On my main page, I have a link to <a href="/project/{{project.id}}">, which will successfully load the template and direct me to http://localhost/project/3 or whatever ID I have specified. The problem is when I try to direct my browser to http://localhost/project/3 or refresh the page, the request is going to the Express/Node server, which returns Cannot GET /project/3.
How do I setup my Express routes to accommodate for this? I'm guessing it will require the use of $location in Angular (although I'd prefer to avoid the ugly ?searches and #hashes they use), but I'm clueless about how to go about setting up the Express routes to handle this.
Thanks.
with express 4, you probably want to catch all requests and redirect to angularjs index.html page.
app.use(app.router); doesn't exist anymore and res.sendfile is deprecated, use res.sendFilewith an uppercase F.
app.post('/projects/', projectController.createProject);
app.get('/projects/:id', projectController.getProject);
app.get('*', function (req, res) {
res.sendFile('/public/index.html');
});
put all your API routes before the route for every path app.get('*', function (req, res){...})
I would create a catch-all handler that runs after your regular routes that sends the necessary data.
app = express();
// your normal configuration like `app.use(express.bodyParser());` here
// ...
app.use(app.router);
app.use(function(req, res) {
// Use res.sendfile, as it streams instead of reading the file into memory.
res.sendfile(__dirname + '/public/index.html');
});
app.router is the middleware that runs all of your Express routes (like app.get and app.post); normally, Express puts this at the very end of the middleware chain automatically, but you can also add it to the chain explicitly, like we did here.
Then, if the URL isn't handled by app.router, the last middleware will send the Angular HTML view down to the client. This will happen for any URL that isn't handled by the other middleware, so your Angular app will have to handle invalid routes correctly.
I guess I should have clarified that I wasn't interested in using a template engine, but having Angular pull all of the HTML partials on it's own, Node is functioning completely as a static server here (but it won't be for the JSON API. Brian Ford shows how to do it using Jade here: http://briantford.com/blog/angular-express.html
My app is a single-page app, so I created an Express route for each possible URL pattern, and each of them does the same thing.
fs.readFile(__dirname + '/public/index.html', 'utf8', function(err, content) {
res.send(content);
});
I was assuming I would have to pass some request variables to Angular, but it looks like Angular takes care of it automatically.

Resources