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

使用Socket.io搭建用户-客服聊天系统时消息发送异常求助

用户-客服聊天系统消息异常问题排查与修复

问题现象

  • 客户端发送消息后,自己看不到消息,但其他客户端能接收
  • 发送第二条消息时,第一条消息会被第二条替换,后端Map中能看到所有消息但前端显示异常

后端代码错误与修复

1. 消息发送范围错误(导致自己看不到消息)

在ROOM:NEW_MESSAGE事件处理中,使用socket.to(roomId).emit只会将消息发送给房间内除当前发送者外的其他客户端,发送者自身收不到推送。需要改为io.to(roomId).emit,这样房间内所有客户端(包括发送者)都能收到消息。

2. 历史消息获取逻辑错误

app.get("/rooms/:id")中,rooms.get(roomId).get("messages")是数组类型,但调用了values()方法(此方法属于Map,数组没有该方法),导致返回结果异常。需直接取数组本身。

修复后的后端代码片段

app.get("/rooms/:id", (req, res) => {
  const roomId = req.params.id;
  const obj = rooms.has(roomId)
    ? { messages: rooms.get(roomId).get("messages") } // 直接取数组,去掉.values()
    : { messages: [] };
  res.send(obj);
});

// ...

io.on("connection", (socket) => {
  // ...

  socket.on("ROOM:NEW_MESSAGE", ({ roomId, name, text }) => {
    const obj = { name, text };
    rooms.get(roomId).get("messages").push(obj);
    io.to(roomId).emit("ROOM:NEW_MESSAGE", obj); // 替换为io.to,包含发送者
  });

  // ...
});

前端代码错误与修复

状态更新闭包陷阱(导致消息被替换)

监听ROOM:NEW_MESSAGE的useEffect依赖项为空数组,闭包捕获的freshData始终是初始的空数组,每次更新都会变成[...空数组, newMessage],最终只保留最后一条消息。需使用函数式更新获取最新的状态值。

修复后的前端代码片段

useEffect(() => {
  socket.on("ROOM:NEW_MESSAGE", (message) =>
    // 使用函数式更新,获取最新的prev状态
    setFreshData(prevFreshData => [...prevFreshData, message])
  );
  socket.on("ROOM:JOINED", (users) => {
    console.log("new user", users);
  });
}, []);

可选优化:发送消息后直接本地更新状态,减少等待后端推送的延迟

const onSendMessage = () => {
  const newMessage = {
    roomId: socketData.roomId,
    text: messageValue,
    name: socketData.name,
  };
  socket.emit("ROOM:NEW_MESSAGE", newMessage);
  // 本地直接添加消息
  setFreshData(prev => [...prev, {name: newMessage.name, text: newMessage.text}]);
  setMessageValue("");
};

内容的提问来源于stack exchange,提问作者Daniil Galitskii

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:10:37