Why do I see a new sess: key in redis on every request?

I have a simple node.js server testing the connect-redis module as a session store. It all works but I've noticed that I get a new sess: key in redis on every single request. I expected only one key since there is only one session.

redis-cli showing multiple sess: keys

Here's my code :

var connect = require('connect');
var util = require("util");
var RedisStore = require("connect-redis")(connect);
var http = require('http');

var app = connect()
  .use(connect.cookieParser('keyboard cat'))
  .use(connect.query())
  .use(connect.session( {
      secret:"elms",
      store:new RedisStore({prefix:'sid_'}),
      cookie:{maxAge:60000, secure:false}
    }))
  .use(function(req, res, next) {
    var sess = req.session;
    if (sess.views) {
      res.setHeader('Content-Type', 'text/html');
      res.write("<p>" + util.inspect(req.cookies) + "</p>");
      sess.basket = sess.basket || {book1:0, book2:0, book3:0};
      if(req.query.buyBook1) {sess.basket.book1 ++;}
      if(req.query.buyBook2) {sess.basket.book2 ++;}
      if(req.query.buyBook3) {sess.basket.book3 ++;}
      if(req.query.expiresession) {
        sess.cookie.maxAge = 0;
      }
      res.write('<p>views: ' + sess.views + '</p>');
      res.write('<ul>\
                  <li>book1 ' + sess.basket.book1 + ' - <a href="/?buyBook1=true">Add</a></li>\
                  <li>book2 ' + sess.basket.book2 + ' - <a href="/?buyBook2=true">Add</a></li>\
                  <li>book3 ' + sess.basket.book3 + ' - <a href="/?buyBook3=true">Add</a></li>\
                </ul>\
                <a href="/?expiresession=true">Expire session</a>');
      res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>');
      res.write('<p>httpOnly: ' + sess.cookie.httpOnly + '</p>');
      res.write('<p>path: ' + sess.cookie.path + '</p>');
      res.write('<p>domain: ' + sess.cookie.domain + '</p>');
      res.write('<p>secure: ' + sess.cookie.secure + '</p>');
      sess.views ++;
    } else {
      sess.views = 1;
    }

    res.write("<p>" + util.inspect(req.cookies) + "</p>");
    res.end('welcome to the session demo. refresh!');
  });
http.createServer(app).listen(3000);

I've noticed that the req.session.cookie.domain is always null. I'm on windows 8 and using the hosts file to map 127.0.0.1 to www.gaz-node.com, which is what I exepected the cookie domain to be at the server. Could be related.

Any ideas? Thanks

The answer was very simple. I got up especially early on this sunday morning in order to debug it and the answer became suddenly clear midway through my first mug of coffee, which subsequently tasted better than the first half.

The Revenge of the /favicon.ico Request

I wasn't handling the request from the browser for /favicon.ico which is bit of a gotcha for node newbies like me. Every request is followed by a /favicon.ico request (by Chrome at least) so the browser can display the site's icon. It never gives up until it gets a favicon.ico.

The actual session was working perfectly well, there was only one session id for that but the request for /favicon.ico doesn't send any cookies over and it was this that was triggering a new zombie session every request.

To fix this I added a module to handle the /favicon.ico request and serve a 404 response. I could just as easily have given the relentless browser a favicon and sent that instead using the "fs" module.

It's important that you handle the /favicon.ico and end the response, without calling next(), before you use the session module! Here's the fixed code :

var connect = require('connect');
var util = require("util");
var RedisStore = require("connect-redis")(connect);
var http = require('http');

var app = connect()
  .use(function(req, res, next) {
    if(req.url == '/favicon.ico') {
      serve404(res);
    } else {
      next();
    } 
  })
  .use(connect.cookieParser())//"elms123"))
  .use(connect.query())
  .use(connect.session( {
      secret:"elms123",
      store:new RedisStore({prefix:'sid_'}),
      cookie:{maxAge:60000, secure:false, domain:"gaz-node.com"}
    }))
  .use(function(req, res, next) {
    var sess = req.session;
    res.setHeader('Content-Type', 'text/html');
    res.write('welcome to the session demo. refresh!');
    if (sess.views) {

      res.write("<p>" + util.inspect(req.cookies) + "</p>");
      sess.basket = sess.basket || {book1:0, book2:0, book3:0};
      if(req.query.buyBook1) {sess.basket.book1 ++;}
      if(req.query.buyBook2) {sess.basket.book2 ++;}
      if(req.query.buyBook3) {sess.basket.book3 ++;}
      if(req.query.expiresession) {sess.cookie.maxAge=0;}
      if(req.query.forceerror) {/*idontexist()*/throw new Error('ahhhh!');}

      res.write('<p>views: ' + sess.views + '</p>');
      res.write('<ul>\
                  <li>book1 ' + sess.basket.book1 + ' - <a href="/?buyBook1=true">Add</a></li>\
                  <li>book2 ' + sess.basket.book2 + ' - <a href="/?buyBook2=true">Add</a></li>\
                  <li>book3 ' + sess.basket.book3 + ' - <a href="/?buyBook3=true">Add</a></li>\
                </ul>\
                <a href="/?expiresession=true">Expire session</a>\
                <a href="/?forceerror=true">Force error</a>');
      res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>');
      res.write('<p>httpOnly: ' + sess.cookie.httpOnly + '</p>');
      res.write('<p>path: ' + sess.cookie.path + '</p>');
      res.write('<p>domain: ' + sess.cookie.domain + '</p>');
      res.write('<p>secure: ' + sess.cookie.secure + '</p>');
      sess.views ++;
    } else {
      sess.views = 1;
    }

    res.end("<p>" + util.inspect(req.cookies) + "</p>");
  })
  .use(connect.errorHandler());
http.createServer(app).listen(3000);

function serve404(res) {
  res.writeHead(404, {"content-type": "text/plain"});
  res.end("Error : Resource not found");
}

I also had this issue. Of course, we should use 'favicon' midlleware. And be sure to place 'session' middleware below 'static'. See my answer http://stackoverflow.com/a/21094838/3190612