Nodejs: Express + RedisStore, req.session undefined
Asked Answered
S

2

5

I have done this before... I don't follow what I'm doing wrong this time, but I've been struggling for a couple of hours and now consider myself mentally blocked. The corresponding code:

app.use(express.bodyParser());
app.use(i18next.handle);
app.use(express.methodOverride());
app.use(express.static(__dirname + '/public'));
app.set('views', __dirname + '/views');
app.set('view engine', 'swig');
app.set('view cache', false);
var session_store = new RedisStore({ client : redis_client});
app.use(express.errorHandler({ dumpExceptions : true, showStack : true}));
app.use(express.cookieParser());
app.use(express.session({ store : session_store, secret : SESSION_SECRET, key : "sid" }));
app.use(app.router);

Then when handling requests, here's just an example:

app.get('/session_test', function (req, res, next) {
  console.log(req.session); //undefined
});

Connection to redis is working just fine. No errors are shown. Then, when trying to access it from the request, the req.session is undefined. The browser is sending the correct sid.

I'm no expert on the exact flow that occurs during the request, but after debugging, it seems as if the router was being called before the session middleware.

Thanks in advance for any and all the likely help. I will provide any code I can, I'm unsure what might be of your help.

Here's more code. server.js

  //Dependency modules
var express = require('express'),
  app = express.createServer(),
  //Application dependency modules
  settings = require('./settings'), //app settings
  routes = require('./routes'), //http routes
  rtroutes = require('./rtroutes'); //real time communication routes (io)

var io = require('socket.io').listen(app);
var appWithSettings = settings.setup(io, app);

routes.settings.setup(appWithSettings);
rtroutes.settings.setup(io, appWithSettings);

No routes are added until routes.settings.setup is called. settings (which is the global settings) is a pretty big file. That's where all configuration is done. Settings are not added until settings.setup method is called too. Here's a cut of the file:

//Dependency modules
var express = require('express'),
  redis = require('redis'),
//Important configuration values
var SESSION_SECRET = 'some secret thing which doesnt belong to stackoverflow!',
    insert_other_variables_here = "lalala";

//Computed general objects

var RedisStore = require('connect-redis')(express),
  redis_client = redis.createClient(REDIS_PORT, REDIS_HOST);

exports.setup = function (io, app) {
  app.configure(function () {
    app.use(express.bodyParser());
    app.use(i18next.handle);
    app.use(express.methodOverride());
    app.use(express.static(__dirname + '/public'));
    app.set('views', __dirname + '/views');
    app.set('view engine', 'swig');
    app.set('view cache', false);
    var session_store = new RedisStore({ client : redis_client});
    app.use(express.errorHandler({ dumpExceptions : true, showStack : true}));
    app.use(express.cookieParser());
    console.log("ABOUT TO ADD SESSION STORE MIDDLEWARE");
    app.use(express.session({ store : session_store, secret : SESSION_SECRET, key : "sid" }));
    console.log("AND NOW ADDED THE SESSION STORE MIDDLEWARE");
    app.use(app.router);
  });

  app.configure('development', function () {
     //some things in here, but nothing that affects app. I have commented this
     //for debugging and it changed nothing
  });

  app.configure('production', function () {
    //mostly configuration for io and some caching layers, as well as servers info
    app.use(express.errorHandler());
    app.use(express.logger({ stream : logFile }));
  });
  app.listen(WEB_PORT);
  return {
    app : app,
    //some other stuff that isn't relevant
  }
}

I have 25 routes split in 4 different files (somehow I didn't have a need for session until now, since I was delaying some parts and everything needed was done with Mongoose). Here's an example of how it is being done (with fake names):

routes/index.js

export.settings = require("./settings");

routes/settings.js

exports.setup = function (app_settings) {
  require("./route1")(app_settings);
  require("./route2")(app_settings);
  require("./route3")(app_settings);
};

Here's a stripped out "route1" file ("routes/route1.js"):

module.exports = function (app_settings) {
  var app = app_settings.app;
  console.log("ABOUT TO ADD ROUTES")
  app.get("/signin", function (req, res, next) {
    console.log(req.session); //this will be undefined
  });
  app.get("/register", function (req, res, next) {
  });
  app.get('/language', function (req, res, next) {
  });
  app.post('/settings', function (req, res, next) {
  });
  console.log("ADDED ROUTES NOW!")
}
Shanley answered 3/10, 2012 at 18:56 Comment(6)
you have this line in there twice: app.use(express.session({ store : session_store, secret : SESSION_SECRET, key : "sid" }));Hales
My bad, I pasted the code twice (all lines were twice in there)Shanley
did that fix the problem? I don't see where you are using req.sessionHales
no, that happened when I pasted the code into here (I never had that double in my code). I will provide a sample of how req.session is undefined.Shanley
can u post your entire server.js file?Preterit
Just added it. Hopefully this serves for a purpose.Shanley
C
9

Whenever you define a route, the router gets automatically inserted into whatever the middleware stack is at the time (subsequent attempts to insert it deliberately will be ignored). Are you sure you aren't defining any routes before you set the session handler?

Calloway answered 3/10, 2012 at 22:45 Comment(3)
Yes. That's an idea that cruised my mind... So I put console.log right before and after adding session middleware, and also before and after adding routes and the output comes first for the session (but before and after adding) and then for routes. Is it possible that middleware order is reset by some action of mine?Shanley
You could try moving your invocation of static to after the invocation of router. I'm not familiar with i18next so I don't know whether that could be causing the problem. You might also try moving errorhandler to the end of the stack; it's possible that where it is now, it's missing an error originating in session.Calloway
I commented out i18next and errorhandler without it getting fixed. I moved static below app.router (notice I disable static for production, since I use nginx for that) and still didn't help. I still think you're on the right track, but I'm not sure where I screwed up :(Shanley
S
3

Forgot to update this: Ebohlman set me in the right track.

It was i18next. When calling one of the init method it sets up routes and it was forcing app.router to be forced into the handle stack sooner. My bad, I didn't realize that part of the code was interacting with the app object and it did. There was no way the question could have been answered better than how he did with the information I gave, so I am marking his answer as right.

I should try sleeping more v.v

Shanley answered 4/10, 2012 at 10:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.