浏览器刷新时如何追踪Socket.IO的新socket id?
问题核心原因
浏览器刷新会触发Socket连接断开重连,新连接会生成全新的socketId,但你的代码存在两个关键问题:
- 用户重连时,服务端仅添加新用户而非更新已有用户的
socketId,导致onlineUsers数组中留存旧的无效ID; - 用户断开连接时,未从
onlineUsers中移除对应记录,数组会堆积无效数据,进一步导致通知无法发送到新连接。
解决方案:更新用户SocketID管理逻辑
服务端代码修改
核心优化点:
- 新增
upsertUser函数,实现用户SocketID的「更新/新增」逻辑; - 断开连接时根据
socketId移除用户记录; - 增加接收方离线的判断逻辑,方便调试。
修改后的server.js代码:
const io = new Server(server, { cors: { origin: "http://localhost:3000", }, }); let onlineUsers: any = []; // 新增:更新或添加用户的socketId const upsertUser = (username: any, socketId: any) => { const existingUserIndex = onlineUsers.findIndex(user => user.username === username); if (existingUserIndex !== -1) { // 用户已存在,替换为新的socketId onlineUsers[existingUserIndex].socketId = socketId; } else { // 新用户,添加到数组 onlineUsers.push({ username, socketId }); } console.log("当前在线用户:", onlineUsers); }; const getUser = (username: any) => { return onlineUsers.find((user: any) => user.username === username); }; // 新增:根据socketId移除离线用户 const removeUser = (socketId: any) => { onlineUsers = onlineUsers.filter(user => user.socketId !== socketId); }; io.on("connection", (socket) => { console.log("用户连接,socketId:", socket.id); socket.on("newUser", (username: any) => { console.log("用户上线:", username); upsertUser(username, socket.id); }); socket.on("sendNotification", ({ senderName, receiverName, action }) => { const receiver = getUser(receiverName); if (receiver) { io.to(receiver.socketId).emit("getNotification", { senderName, action, }); } else { console.log(`接收方${receiverName}已离线`); } }); socket.on("disconnect", () => { console.log("用户断开连接,socketId:", socket.id); removeUser(socket.id); }); });
客户端代码优化
核心优化点:
- 初始化Socket时直接发送用户信息,避免依赖异步状态更新;
- 添加监听清理逻辑,防止重复绑定导致通知多次触发。
修改后的客户端代码:
// 初始化Socket并发送用户信息 useEffect(() => { const newSocket = io("http://localhost:5000"); setSocket(newSocket); // 连接成功后立即发送用户信息,无需等待state更新 const userData = localStorage.getItem("user"); if (userData) { const user = JSON.parse(userData); newSocket.emit("newUser", user.name); } }, []); // Navbar组件的通知监听逻辑 React.useEffect(() => { if (!socket) return; const handleNotification = (data: any) => { console.log("收到通知:", data); setNotifications(prev => [...prev, data]); }; socket.on("getNotification", handleNotification); // 组件卸载时移除监听,防止内存泄漏 return () => { socket.off("getNotification", handleNotification); }; }, [socket]);
流程验证
- 页面刷新时:旧Socket触发
disconnect事件,服务端移除旧socketId的用户记录; - 新页面加载:创建新Socket连接,立即发送
newUser事件,服务端upsertUser更新该用户的socketId为新值; - 后续发送通知:
getUser拿到最新的有效socketId,通知能正常推送到新连接。
额外建议
- 如果支持用户多设备登录,可将
onlineUsers中用户的socketId改为数组,存储同一用户的所有在线连接,实现多设备同步通知; - 生产环境建议用Redis等数据库存储在线用户信息,避免服务器重启后数据丢失。
内容的提问来源于stack exchange,提问作者noob_developer
相关产品推荐
相关产品推荐

