Socket.io获取用户名后客户端接收数据显示undefined问题排查
I've got my feature mostly working as expected, but I'm running into an issue with Socket.io. Here's my modified code for the
/gameroute://Route to game app app.get('/game', function (req, res) { if (req.user) { res.render('game'); // Socket stuff io.on('connection', function (socket) { var dataObj = { id: req.user.id, username: req.user.username, }; socket.emit('startup', dataObj); console.log(dataObj.username); // This logs correctly // Server Time var interval = setInterval(function () { var momentNow = moment(); var data = momentNow.format('LT'); socket.emit('time', data); }, 60000); // Chat - Needs work socket.on('chat', function (msg) { message = msg; io.emit('message', { message: message }); }); }); } else { req.flash('error', 'You need to be signed in!'); res.redirect('/'); } });I structured it this way so I could access the user data in the Socket.io section, but now when the client runs:
socket.on('startup', function (dataObj) { console.log(dataObj.username); // Logs undefined });The console shows
undefined, even though the server logs the username just fine. Why isn't the client receiving the data correctly?
Let's break down what's going wrong here, and fix it:
The Core Problem
You're registering a global connection event listener inside your /game route handler. Every time a user visits /game, you add a new io.on('connection') callback. This creates two critical issues:
- When a socket connects later, all the accumulated callbacks will fire—not just the one tied to the current user's request.
- The
req.userinside the callback doesn't belong to the socket that just connected. By the time the socket connection is established, the original HTTP request for/gamehas already finished, soreqis a stale object from a previous request (or even the wrong user entirely).
That's why the server logs a username (from the stale req.user), but the client gets undefined or incorrect data—your startup event might be sent multiple times, or the dataObj is tied to someone else's session.
Step-by-Step Fixes
1. Move the connection listener outside your route handler
Never register io.on('connection') inside a route. It should be set up once when your server starts, not per request.
2. Access user data from the socket's handshake
To get the correct user for a socket connection, you need to leverage Socket.io's handshake context. If you're using Passport (which it looks like you are), configure Socket.io to access your existing session middleware:
// At the top of your server file, after setting up app and io const sessionMiddleware = app.get('sessionMiddleware'); // Get your existing session middleware io.use((socket, next) => { sessionMiddleware(socket.request, {}, next); }); // Set up the connection listener ONCE io.on('connection', function (socket) { // Get the actual user tied to this socket const user = socket.request.user; if (!user) { // Handle unauthenticated sockets if needed socket.disconnect(); return; } const dataObj = { id: user.id, username: user.username, }; socket.emit('startup', dataObj); console.log(dataObj.username); // Server Time logic const interval = setInterval(function () { const momentNow = moment(); const data = momentNow.format('LT'); socket.emit('time', data); }, 60000); // Clean up the interval when the socket disconnects (prevents memory leaks) socket.on('disconnect', () => { clearInterval(interval); }); // Chat logic socket.on('chat', function (msg) { io.emit('message', { message: msg }); }); });
3. Simplify your /game route
Now your route only needs to handle authentication and rendering the page:
app.get('/game', function (req, res) { if (req.user) { res.render('game'); } else { req.flash('error', 'You need to be signed in!'); res.redirect('/'); } });
Why This Works
- The
connectionlistener runs once, so no duplicate callbacks fire for new sockets. socket.request.usergives you the actual user associated with the current socket connection, not a stalereqfrom a finished HTTP request.- You're cleaning up the interval when the socket disconnects, which prevents memory leaks from abandoned timers.
Give this a try—your client should now receive the correct username in the startup event.
内容的提问来源于stack exchange,提问作者William

