You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Socket.io获取用户名后客户端接收数据显示undefined问题排查

Socket.io 'startup' event returns undefined username on client, even though server logs it correctly

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 /game route:

//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:

  1. When a socket connects later, all the accumulated callbacks will fire—not just the one tied to the current user's request.
  2. The req.user inside the callback doesn't belong to the socket that just connected. By the time the socket connection is established, the original HTTP request for /game has already finished, so req is 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 connection listener runs once, so no duplicate callbacks fire for new sockets.
  • socket.request.user gives you the actual user associated with the current socket connection, not a stale req from 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:20:59