Isaac Krementsov
Isaac Krementsov

Reputation: 706

How to pass request session data to websockets on HTTP upgrade in NodeJS

I am trying to make a livechat that uses session data, but I can't seem to pass session data to websockets. I have tried all solutions I can find but they all give me errors. HTTP requests are forwarded via a manual upgrade event, where I can access the request object. However, I can't get to req.session (it returns undefined, even when I add data) from there, so I can't pass it to WebSockets. Here is my server-side code:

var express = require('express');
var app = express();
var server = require('http').Server(app); 
var session = require('express-session');
var mongoose = require('mongoose');
var ejs = require('ejs');
var path = require('path');
var ws = require('ws');
var wss = new ws.Server({noServer:true});
app.set('views', path.join(__dirname, './views'));
app.use(express.static(path.join(__dirname, './public')));
app.set('view engine', 'ejs');
app.use(session({
  saveUninitialized: true,
  resave: true,
  cookie: {httpOnly: true}
}));
app.set('port', process.env.PORT || 3000);
server.listen(3000, function(){
    console.log('listening on 3000')
})
server.on('upgrade', function(req,socket,head){
    var pathname = require('url').parse(req.url).pathname;
    //req.session returns undefined here, so I can't pass it to my WebSocket handler
    if(pathname == '/' || ''){
        wss.handleUpgrade(req, socket, head, function(ws){
            wss.emit('connection', ws)
        })
    }
});
app.get('/', function(req,res){
    res.render('index')
});
var connections = [];
function broadcast(data, users){
    for(let i = 0; i < users.length; i++){
        if(users[i].readyState == ws.OPEN){
            users[i].send(data)
        }
    }
}
wss.on('connection', function(connection){
    var index = connections.push(connection) - 1;
    broadcast('joined!', connections);
    connection.on('message', function(msg){
        broadcast(msg, connections)
    })
    connection.on('close', function(){
        connections.splice(index, 1);
        broadcast('User disconnected', connections)
    })
})

Upvotes: 2

Views: 1556

Answers (1)

Perspectivus
Perspectivus

Reputation: 990

This is an old question, but just in case anyone runs into the same problem, I found the solution in this expressjs issue.

In the context of the above code, the solution would be to first store the express-session RequestHandler function in a variable:

const sessionParser = session({
  saveUninitialized: true,
  resave: true,
  cookie: {httpOnly: true}
});

app.use(sessionParser);

... and then call that function in the callback of server.on('upgrade'... like this:

server.on('upgrade', function(req, socket, head) {
    sessionParser(req, {}, () => {
        // req.session should be defined at this point
        if (condition) {
            wss.handleUpgrade(req, socket, head, function(ws){
                wss.emit('connection', ws, request);
            });
        }
    });
});

Upvotes: 1

Related Questions