Sessions won't save in Node.js without req.session.save()

33,179

Okay, so, I've figured it out. I'll put the answer here for anyone else that happens to get caught on this.

For GET requests, the server assumes that you're going to be sending data back, and will automatically save session data once the route is fully processed.

For POST requests (what I'm using), however, the same assumption isn't made. Session states are only saved in one of two conditions - either when data is being sent out (through res.send, res.redirect, etc.), or if you manually call req.session.save(). I was already calling /login from an AJAX request, I just wasn't returning anything if certain conditions were met. Having the server respond to the client with some data after setting the session variable fixed this.

Share:
33,179
PuppyKevin
Author by

PuppyKevin

Updated on October 04, 2020

Comments

  • PuppyKevin
    PuppyKevin over 3 years

    I'm building a website using Node.js, Express, and Redis for session management. For whatever reason, if I have a session variable (isLoggedIn in this example), and I refresh the page, the variable doesn't get saved, however, if I call req.session.save() after setting the variable, it does get saved to Redis (redis-cli monitor shows this - not calling save() shows that the variable isn't there, whereas calling save() shows it).

    I'm using this to set up and start the server:

    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 swig = require('swig');
    var session = require('express-session')
    var RedisStore = require('connect-redis')(session);
    
    var routes = require('./routes/index');
    var users = require('./routes/users');
    
    var app = express();
    
    // Configure the favicon first. This avoids other middleware from processing the request if we know the request is for the favicon.
    app.use(favicon(__dirname + '/public/images/favicon.ico'));
    
    // All other requests will require everything else.
    
    // Set up the view engine.
    app.set('view engine', 'html');
    app.set('views', path.join(__dirname, '/views'));
    app.engine('html', swig.renderFile);
    
    // Set up our logger.
    app.use(logger('dev'));
    
    // Set up JSON parsing.
    app.use(bodyParser.json());
    
    // Set up encoded URL parsing.
    app.use(bodyParser.urlencoded());
    
    // Set up the cookie parser.
    app.use(cookieParser('thedogsleepsatnight'));
    
    // Set up our session store. This will use Redis as our session management.
    app.use(session({
        resave: true,
        saveUninitialized: true,
        secret: "thedogsleepsatnight",
        store: new RedisStore()
    }));
    
    app.use(require('stylus').middleware(path.join(__dirname, 'public')));
    app.use(express.static(path.join(__dirname, 'public')));
    
    app.use('/', routes);
    

    And then, in that route, I have:

    var express = require('express');
    var router = express.Router();
    
    router.get('/', function(req, res) {
        console.log(req.session.isLoggedIn);
        if (req.session.isLoggedIn) {
            console.log("Logged in!");
        } else {
            console.log("Not logged in");
        }
    
        res.render('index');
    });
    
    router.post('/login', function(req, res) {
        console.log("Going to set isLoggedIn. Currently: " + req.session.isLoggedIn);
        req.session.isLoggedIn = true;
        console.log("Set isLoggedIn. Currently: " + req.session.isLoggedIn);
    });
    
    module.exports = router;
    

    From that, I should be able to navigate to /login, have the session set isLoggedIn to true, and that should save automatically to Redis. After that, heading to / should tell me that I'm logged in. Loading /login does set the variable, the second log shows that, but loading / says that I'm not logged in. redis-cli monitor shows

    1414076171.241836 "setex" "sess:FIDJ9qDbX_0u9pzlC6VZEW76zZcyiPME" "86400" "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"}}"
    

    upon saving, which doesn't include the isLoggedIn variable, but adding in req.session.save() shows:

    1414076475.601644 "setex" "sess:FIDJ9qDbX_0u9pzlC6VZEW76zZcyiPME" "86400" "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"isLoggedIn\":true}"
    

    Any idea on why I have to call req.session.save() when all of the examples I've seen don't use it?