Node.js Socket.io项目:添加Socket属性后获取username返回undefined
问题解决:Socket.io中socket.data.username在leave事件中返回undefined
可能原因与对应解决方法
1. Socket.io版本兼容性问题
如果你的Socket.io版本低于3.x,socket.data这个API还不存在,直接使用会导致属性未定义。此时可以直接将用户名挂载到socket实例上替代socket.data.username:
// join game事件中 socket.username = username; // leave game事件中 console.log(socket.username + ' left the game'); connectedUsers.delete(socket.username);
若使用4.x+版本,socket.data是官方推荐的连接数据存储方式,问题大概率出在客户端逻辑或连接生命周期上。
2. 客户端触发leave事件时连接已更换
当用户通过页面跳转(如window.location.href)进入/game页面时,浏览器会断开原WebSocket连接,新页面会建立全新的socket连接——这个新连接从未触发过join game事件,自然没有username属性。
解决办法:
- 跳转前先触发
leave game事件,确保原连接完成清理:// 客户端代码 socket.emit('leave game', () => { window.location.href = '/game'; }); - 改用单页应用路由(如React Router、Vue Router),避免页面刷新,保持socket连接的持续性。
3. 未处理意外断开的情况
用户直接关闭页面或网络中断时,不会主动触发leave game事件,此时需要监听socket的disconnect事件来清理用户名。
修正后的完整服务端代码
io.on('connection', (socket) => { console.log('a user connected'); io.emit('update users', Array.from(connectedUsers)); socket.on('join game', (username) => { console.log(username + ' joined the game'); // 避免重复添加同名用户 if (!connectedUsers.has(username)) { connectedUsers.add(username); socket.data.username = username; io.emit('update users', Array.from(connectedUsers)); } socket.emit('redirect', '/game'); }); socket.on('leave game', () => { if (socket.data.username) { console.log(socket.data.username + ' left the game'); connectedUsers.delete(socket.data.username); io.emit('update users', Array.from(connectedUsers)); delete socket.data.username; } }); // 处理意外断开连接的情况 socket.on('disconnect', () => { if (socket.data.username) { console.log(socket.data.username + ' disconnected'); connectedUsers.delete(socket.data.username); io.emit('update users', Array.from(connectedUsers)); } }); });
额外注意事项
- 加入用户前检查
connectedUsers中是否已存在同名用户,避免重复添加。 - 在
leave game和disconnect事件中先判断username是否存在,避免出现undefined left the game的无效日志。
内容的提问来源于stack exchange,提问作者James Kohls
相关产品推荐
相关产品推荐

