Socket.io活跃用户列表旧标签页在用户断线重连后不更新的原因是什么?
在线用户列表状态不同步修复方案
核心问题根因
- 服务端用户登录逻辑仅在socket连接初始化时广播一次在线用户,用户后续登录成功不会主动推送最新状态,导致旧标签页收不到重新上线的通知
- 服务端存储用户socket连接时直接覆盖原有数组,会丢失同一个用户其他标签页的连接记录
- 客户端通过
record数组对上线用户做去重,同一个用户重新上线时因为用户ID已存在于数组中,不会触发重新渲染 - 用户登出/断开连接时,服务端没有清理
users对象中对应的失效连接记录
服务端代码修复
let users = {}; io.on("connection", async (socket) => { // 登录逻辑优化 socket.on("login", async function(user_id) { socket.handshake.session.user_id = user_id; await socket.handshake.session.save(); // 存储socket连接,不覆盖原有连接 if (!users[user_id]) { users[user_id] = []; } if (!users[user_id].includes(socket.id)) { users[user_id].push(socket.id); } // 登录成功后广播最新在线用户列表 await broadcastOnlineUsers(); }); // 登出逻辑优化 socket.on("logout", async function(user_id) { if (socket.handshake.session.user_id) { delete socket.handshake.session.user_id; await socket.handshake.session.save(); // 清理当前socket连接记录 if (users[user_id]) { users[user_id] = users[user_id].filter(id => id !== socket.id); if (users[user_id].length === 0) { delete users[user_id]; } } await broadcastOnlineUsers(); } }); // 连接初始化逻辑优化 const currentSession = socket.handshake.session.user_id; if (typeof currentSession !== "undefined" && typeof socket.id !== "undefined") { if (!users[currentSession]) { users[currentSession] = []; } if (!users[currentSession].includes(socket.id)) { users[currentSession].push(socket.id); } await broadcastOnlineUsers(); } // 断开连接逻辑优化 socket.on("disconnect", async () => { const userId = socket.handshake.session.user_id; if (userId && users[userId]) { // 清理失效连接 users[userId] = users[userId].filter(id => id !== socket.id); if (users[userId].length === 0) { delete users[userId]; const userLeft = await utils.getUserInfo(userId); io.emit("msg", utils.formatMessage("Bot", `${userLeft.name} has left the chat`)); } await broadcastOnlineUsers(); } }); // 封装统一的在线用户广播方法 async function broadcastOnlineUsers() { const onlineUserIds = Object.keys(users); const onlineUsers = []; for (const userId of onlineUserIds) { // 过滤掉所有连接都失效的用户 const validSockets = users[userId].filter(id => io.sockets.sockets.has(id)); if (validSockets.length > 0) { users[userId] = validSockets; onlineUsers.push(await utils.getUserInfo(userId)); } else { delete users[userId]; } } // 统一广播全量在线用户列表 io.emit("onlineUsersUpdate", onlineUsers); } })
客户端代码修复
// 统一监听全量在线用户更新事件,移除原有重复判断逻辑 socket.on("onlineUsersUpdate", onlineUsers => { const ul = document.querySelector(".the-ul"); // 清空现有列表 ul.innerHTML = ""; // 重新渲染所有在线用户 onlineUsers.forEach(user => { outputActiveUsers(user); }); }) // 保留原有业务逻辑不变 async function outputMessage(msg){ let div=document.createElement("div"); div.classList.add("msg-wrapper"); div.innerHTML=`<div class="msg-wrapper"> <div class="msg"> <p>${msg.text}</p> </div> <span id="you-time" class="time">${msg.time}</span> </div>`; document.querySelector(".msg-wrapper").appendChild(div); } function outputActiveUsers(msg){ let li=document.createElement("li"); li.classList.add("active-people-li"); li.innerHTML= `<div class="active-sidebar"> <div class="div-of-img"> <img src="../files/profile.png" alt="" class="active-profile-img"> </div> <div> <a href=""><h4>${msg.name}</h4></a> <h5>Hi. Is this you, bro?</h5> </div> </div>`; document.querySelector(".the-ul").appendChild(li); }
HTML代码无需修改
<div class="active-people"> <ul class="the-ul"> </ul> </div>
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

