Expressjs+socket.io+express-session

2019-02-15 11:52发布

问题:

I have this code in my server.js.

var app = require('express')(),
        session = require('express-session'),
        cookie = require('cookie'),
        cookieParser = require('cookie-parser'),
        manager = require('./sockets/manager');

var sessionStore = new session.MemoryStore();


app.use(cookieParser('secret'));
app.use(session({
    name: 'sid',
    store: sessionStore,
    secret: 'secret',
    saveUninitialized: true,
    resave: true,
    cookie: {
        path: '/',
        httpOnly: true,
        secure: false,
        maxAge: null
    }
}));

var server = require('http').Server(app).listen(8888),
    io = require('socket.io')(server);

io.use(function(socket, next) {
    var data= socket.request;

    if (data.headers.cookie) {
        data.cookie = cookie.parse(cookieParser.signedCookie(data.headers.cookie, 'secret'));

        console.log('data.cookies ( %s )', JSON.stringify(data.cookie)); 
        // print 'io=id_place', cookies doesn't have sid, why?

        if (data.cookie.sid) {
            data.sid = request.cookie.sid;
            sessionStore.get(request.cookie.sid, function(err, session) {
                request.session = session;
            });
        }
    }

    next();
});

manager.use(io);

Console log shows me this cookie request.cookies ( {"io":"lHKSseNH5UrnJisSAAAA"} ). I've just seen many examples with expressjs 3 and socket 0.9, but I have:

"socket.io": "^1.0.6", "express": "~4.5.1", "express-session": "~1.6.4"

and it doesn't work.

Have I any mistakes?

回答1:

I've created solution for you: enter link description here. As you can see socket object has handshake property which include request headers with cookie.



回答2:

The below link has a very simple solution to share session between Express and Socket.IO.

Simple Answer

The middleware API of Express 4.x is so close to Socket.IO 1.x that we can use the same session middleware for both.

The example over there uses MongoDB session store. I tried with the express-session's default session store and it worked.

io.js

var io = require('socket.io')();

io.on('connection', function (socket) {
    console.log(socket.request.session);
    console.log('New client connected!');
});

module.exports = io;

app.js

var express = require('express'),
    path = require('path'),
    favicon = require('serve-favicon'),
    logger = require('morgan'),
    cookieParser = require('cookie-parser'),
    bodyParser = require('body-parser'),
    expressSession = require('express-session'),
    io = require('./io'),

    index = require('./routes/index'),

    app = express(),

    mongoose = require('mongoose'),
    uri = 'localhost:27017/selfie_showcase',
    options = {
        db: { native_parser: true },
        server: { socketOptions: { keepAlive: 1 } },
        replset: { socketOptions: { keepAlive: 1 } },
        user: 'arun',
        pass: 'arun'
    },

    sessionMiddleware = expressSession({
        secret: 'my_s3cr3t_s3ss1on',
        resave: true,
        saveUninitialized: true
    });


// connect to MongoDB
mongoose.connect(uri, options, function(err) {
    if(err) {
        console.log(err);
    }
});

// configure socket.io to share session with express
io.use(function(socket, next) {
    sessionMiddleware(socket.request, {}, next);
});

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(sessionMiddleware);
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);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            title: 'Error',
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        title: 'Error',
        message: err.message,
        error: {}
    });
});


module.exports = app;

bin/www

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var io = require('../io');
var debug = require('debug')('selfie-showcase:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);
io.attach(server);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

Hope this might help any future users.

P.S: I used express-generator so this kind of module split.



回答3:

Try this module express-socket.io-session.

It allows you to shared cookie-based session data between express and socket.io (and viceversa).

You can use whatever storage you want for session data because you create the express-session object in a regular way and then share it with socket.io.

It works for express >4.0 and socket.io >1.0