I'm using Socket.io
in a chat application I'm building. I'm trying to setup the session so that I can persist the login of the users in between sessions.
Here's the relevant code :
index.js (server)
var cookieParser = require('cookie-parser')();
var session = require('cookie-session')({ secret: 'secret' });
app.use(cookieParser);
app.use(session);
io.use(function(socket, next) {
var req = socket.handshake;
var res = {};
cookieParser(req, res, function(err) {
if (err) return next(err);
session(req, res, next);
});
});
io.on('connection', function(socket){
socket.on('test 1', function(){
socket.handshake.test = 'banana';
});
socket.on('test 2', function(){
console.log(socket.handshake.test);
});
});
chat.js (client)
var socket = io();
socket.emit('test 1');
socket.emit('test 2');
The code above works, it will print banana
to the console as expected. However, if I comment out the 'test 1' like so :
var socket = io();
// socket.emit('test 1');
socket.emit('test 2');
It will print undefined
to the console.
Shouldn't it still be able to print banana
, since it's using a session and it's persisting between requests? I also run into the same issue if I inverse the order in which I call 'test 1' and 'test 2'.
What am I doing wrong? What am I missing for the session to persist as expected?
The problem is that you are using a cookie-session
, and socket.io does not allow you to set cookies due specification of XMLHttpRequest
, also you don't have a request/response
in the middle of a web socket transaction, so you cannot set the response cookie.
With your middleware, you can see the cookies, but you cannot set it in socket.io. This can be ensured with this example:
io.use(function(socket, next) {
var req = socket.request;
var res = req.res;
cookieParser(req, res, function(err) {
if (err) return next(err);
session(req, res, next);
});
});
io.on('connection', function(socket){
var req = socket.request;
console.log(req.session.test)
socket.on('test 1', function(){
req.session.test = 'banana';
});
socket.on('test 2', function(){
console.log(req.session.test);
});
});
app.get('/', function(req, res) {
console.log(req.session.test)
if (!req.session.test) {
req.session.test = 'banana request'
}
})
You can use something like redis
to persist the sessions, or some 'hack' to set it in the handshake.
Another option is not use sessions at all, and just set the property in socket
object or in another javascript object, but in this case you cannot share the object between servers/services.
So, example:
io.on('connection', function(socket){
var id = socket.handshake.query.id; //you can set this in client connection string http://localhost?id=user_id
//Validate user, registered etc. and if ok/
if(validateUser(id)) {
//if this is reconnect
if(io.sessions[id]) {
socket.session_id = io.sessions[id].session_id;
} else {
var session_id = random_value;
socket.session_id = some_random_value;
io.sessions[id] = {
user_id: id,
session_id: socket.session_id
};
}
registerEvent(socket);
} else {
socket.emit('auth_error', 'wrong user');
}
});
function registerEvent(socket) {
socket.on('some_event', function(data, callback) {
if(!socket.session_id) {
callback('unathorized');//or emit
socket.emit('auth_error', 'unauthorized');
}
//do what you want, user is clear
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With