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

Socket.io+React+TS问题:连接建立但前端接收数据为undefined

问题排查:Socket.io前端接收newNotification事件时senderId/recipientId为undefined

问题背景

使用Socket.io、React与TypeScript开发时,已成功建立Socket连接,但前端接收后端发送的newNotification事件数据时,senderId和recipientId始终为undefined或null。

后端Socket配置(socket.ts)

import {Server} from "socket.io"
import {createServer} from "http" 
import express from "express"

const app = express();
// Attach Socket.IO server to the HTTP server
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: "http://localhost:5173",
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true,
},
});

const userSocketMap: { [key: string]: string } = {};
export const getRecipientSocketId = (receiverId:string)=>{
return userSocketMap[receiverId]
}

io.on("connection", (socket) => {
console.log("user connected",socket.id);

      const userId = Array.isArray(socket.handshake.query.userId) ? socket.handshake.query.userId[0] : socket.handshake.query.userId;
      if (userId !== undefined) userSocketMap[userId] = socket.id;
    
    
    
      socket.on("error", (error) => {
        console.error("Socket error:", error);
      });
      socket.on("disconnect",() => {
        console.log("user disconnected",socket.id);
        if (userId !== undefined) delete userSocketMap[userId];
      })

})

export{app, io, httpServer}

后端发送通知代码(sendInvitaionCntroller)

import User from "../../db/models/User";
import { Request, Response } from "express";
import { getRecipientSocketId, io } from "../../src/socket";

.....
// Find the sender user
const sender = await User.findById(senderId);
if (!sender) {
return res.status(404).json({
message: "Sender not found.",
data: null,
});
}
const senderUsername = sender.username;
const senderAvatar = sender.avatar;

    // Emit newNotification event with sender data
    const recipientSocketId: string | undefined =
      getRecipientSocketId(recipientId);
    if (recipientSocketId) {
      const notificationData = {
        senderId,
        recipientId,
        senderUsername,
        senderAvatar,
      };
      io.to(recipientSocketId).emit("newNotification", notificationData);

前端接收代码(Header.tsx)

const [notification, setNotification] = useState<{ senderId: string, recipientId: string } |    
null>(null);
 
const { data: senderData } = useGetUserByIdQuery(notification?.senderId || '', {
  skip: !notification || !notification.senderId,
});    
console.log(senderData);
useEffect(() => {
  const socket = io('http://localhost:7000'); 

  socket.on('connect', () => {
    console.log('Connected to the server');
    
    socket.on('newNotification', ({ senderId, recipientId }) => {
      console.log(`New notification received. Sender ID: ${senderId}, Recipient ID:  
       ${recipientId}`);
      
      // Update the state with the new notification
      setNotification({ senderId, recipientId });
    });
    
  });
  return () => {
    socket.disconnect();
    return undefined
  }
}, []);

问题现象

后端已正确触发newNotification事件并发送数据,但前端控制台打印的senderId和recipientId为undefined或null,无法正常处理通知。

预期行为

前端能正常接收后端发送的newNotification事件,获取有效的senderId和recipientId值并更新状态。


排查方向与解决方法

1. 确认后端发送的senderId/recipientId实际值

在后端发送通知的代码中添加日志,直接打印要发送的senderId和recipientId:

console.log('待发送通知的ID:senderId=', senderId, 'recipientId=', recipientId);
const notificationData = {
  senderId,
  recipientId,
  senderUsername,
  senderAvatar,
};
io.to(recipientSocketId).emit("newNotification", notificationData);

如果后端日志显示这两个值本身就是undefined或null,问题出在业务逻辑层(比如获取senderId的环节出错),需要先修正后端的参数获取逻辑。

2. 处理MongoDB ObjectId序列化问题

如果senderId和recipientId是MongoDB返回的ObjectId类型(而非字符串),直接序列化会丢失数据,需要转为字符串后再发送:

const notificationData = {
  senderId: senderId.toString(),
  recipientId: recipientId.toString(),
  senderUsername,
  senderAvatar,
};

3. 调整前端事件监听的时机

当前前端在connect回调内部绑定newNotification监听,可能导致绑定延迟。改为直接在Socket实例上绑定监听:

useEffect(() => {
  const socket = io('http://localhost:7000'); 

  // 直接绑定事件监听,无需嵌套在connect回调
  socket.on('newNotification', (fullData) => {
    console.log('完整接收的通知数据:', fullData); // 先打印完整数据,检查字段是否匹配
    const { senderId, recipientId } = fullData;
    console.log(`New notification received. Sender ID: ${senderId}, Recipient ID: ${recipientId}`);
    setNotification({ senderId, recipientId });
  });

  socket.on('connect', () => {
    console.log('Connected to the server');
  });

  return () => {
    socket.disconnect();
  }
}, []);

通过打印fullData确认字段名是否和后端一致(比如是否拼写错误,如sender_id vs senderId)。

4. 确保前端连接时传递正确的userId

后端依赖socket.handshake.query.userId维护用户Socket映射,前端连接时必须携带当前用户ID:

// 替换为实际登录用户的ID
const currentUserId = 'xxx';
const socket = io('http://localhost:7000', {
  query: { userId: currentUserId }
});

如果前端没传userId,后端的userSocketMap会无效,可能导致通知发送到错误的客户端,甚至无法发送。

5. 检查Socket.io版本兼容性

确保前后端使用的Socket.io版本完全一致(比如均为4.x版本),版本不匹配会导致数据传输异常。同时确认后端CORS配置允许前端的Socket连接请求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 04:25:03