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

新用户连接时socket.username被设为首个用户,其他用户该值为undefined的问题

问题排查与修复

核心问题

  1. 认证中间件注册位置错误:你把io.use()放在了io.on('connection')的回调里,这会导致每有新用户连接就重复注册一次中间件,后续连接的中间件逻辑会混乱,出现用户名被覆盖或未赋值的情况。
  2. 房间映射变量作用域错误:socketRoomMap和socketObject定义在connection回调内部,每个新连接都会创建新的Map/对象,之前用户的房间记录会丢失,也无法跨连接共享数据。

修复后的完整代码

const http = require('http');
const ioServer = require('socket.io');
const jwt = require('jsonwebtoken');
const app = require('./routes/user.routes');
const mongoConnect = require('../database/mongo');
const User = require('../database/models/user.model');
require('dotenv').config();

const server = http.createServer(app);
const io = ioServer(server, { cors: { origin: "*" } });

// 全局认证中间件:放在io.on('connection')外面,只注册一次
io.use(async (socket, next) => {
    try {
        const token = socket.handshake.auth.token;
        const decoded = jwt.verify(token, process.env.SECRET_KEY);
        const user = await User.findById(decoded.userId);
        if (!user) {
            throw new Error('User not found');
        }
        socket.username = user.username;
        console.log('user', socket.username);
        next();
    } catch (error) {
        console.error('Authentication error', error);
        next(new Error('Authentication error'));
    }
});

// 全局房间映射:所有连接共享同一个Map,放在connection外面
const socketRoomMap = new Map();
const socketObject = {};

io.on('connection', (socket) => {
    // Handle 'join' event when a client joins the chat room
    socket.on('join', (room) => {
        socket.join(room);
        socketRoomMap.set(socket.username, room);
        socket.emit('joined', `You joined ${room}`);
        socket.broadcast.emit('user joined', `${socket.username} joined ${room}`);
    });

    // Handle 'chat message' event when a client sends a message
    socket.on('chat message', (room, message) => {
        io.to(room).emit('chat message', `${socket.username}: ${message}`);
    });

    // Handle 'disconnect' event when a client disconnects
    socket.on('disconnecting', () => {
        const room = socketRoomMap.get(socket.username);
        if (room) {
            socket.broadcast.to(room).emit('user left', `${socket.username} left the chat room`);
            socketRoomMap.delete(socket.username);
        }
    });
});

server.listen(3000, () => {
    mongoConnect()
        .then(() => { })
        .catch((error) => {
            console.error('MongoDB connection error:', error);
        });
    console.log('Server started running...');
});

process.on('uncaughtException', (error) => {
    console.error('Uncaught Exception:', error.stack);
    process.exit(1);
});

关键修改说明

  • 调整中间件位置:把io.use()移到io.on('connection')外部,作为Socket.io的全局中间件,确保每个连接只会触发一次认证逻辑,正确给socket.username赋值。
  • 调整变量作用域:将socketRoomMap和socketObject提升到全局作用域,这样所有客户端连接都共用同一个映射表,不会出现房间记录丢失的问题。

内容的提问来源于stack exchange,提问作者Hayatudeen Abdulrahman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 04:35:04