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

Socket.io中getUser(receiverId)返回undefined问题排查修复

Socket.io查询指定用户返回undefined问题修复方案

问题复现

开发React实时聊天应用时,使用Socket.io实现定向消息/通知推送,传入receiverId调用用户查询方法时始终返回undefined,触发报错。问题出在friendRequest事件处理逻辑中,对应代码片段:

socket.on("friendRequest", ({ senderId, receiverId }) => { 
  const receiver = getUser(receiverId); 
  console.log(receiver) 
});

服务端完整代码如下:

const express = require('express');
const socketio = require('socket.io');
const http = require('http');
const cors = require('cors');

const PORT = process.env.PORT || 5000;

const router = require('./router');

const app = express();
const server = http.createServer(app);
const io = socketio(server);


app.use(router);
app.use(cors());

let users = [];
const addUser = (userId, socketId) => {
  !users.some((user) => user.userId === userId) &&
    users.push({ userId, socketId });
};

const removeUser = (socketId) => {
  users = users.filter((user) => user.socketId !== socketId);
};

const getUser = (userId) => {
  return users.find((user) => user.userId === userId);
};
io.on('connect', (socket) => {
  console.log("a user connected.");

  socket.on("addUser", (userId) => {
    addUser(userId, socket.id);
    io.emit("getUsers", users);
  });

  socket.on("sendNotification", ({ senderId, receiverId, type }) => {
    const receiver = getUser(receiverId);
    io.to(receiver.socketId).emit("getNotification", {
      senderId,
      type,
    });
  });

  socket.on("friendRequest", ({ senderId, receiverId }) => {
    const receiver = getUser(receiverId);
    console.log(receiver)
  });

  socket.on("sendText", ({ senderId, receiverId, text }) => {
    const receiver = getUser(receiverId);
    io.to(receiver.socketId).emit("getText", {
      senderId,
      text,
    });
  })

  socket.on("disconnect", () => {
    console.log("User Disconnected", socket.id);
    removeUser(socket.id);
    io.emit("getUsers", users);
  });
});

app.use(router);

server.listen(PORT,() => console.log('Server has started on port ${PORT}'));

根因分析

getUser(receiverId)返回undefined的核心原因是:传入的receiverId无法和在线用户列表users中的记录匹配,常见触发场景包括:

  • 类型不匹配:getUser方法用全等===做匹配,若接收方上线时存的userId是数字类型,前端传的receiverId是字符串类型,会直接判定为不相等
  • 用户未注册上线:接收方建立socket连接后,没有触发addUser事件上报自身userId,服务端在线列表中根本没有该用户的记录
  • 重复连接覆盖:同一账号多端登录、重复建立socket连接时,原有addUser逻辑不会清理旧记录,可能出现userId和socketId映射错乱
  • 代码中存在附加bug:服务端启动日志使用单引号包裹模板字符串,插值语法${PORT}不会生效,会误导端口排查

修复方案

  1. 统一参数类型,增加空值校验,修改所有涉及定向推送的事件逻辑,避免读取undefined属性报错。以friendRequest事件为例,sendNotification、sendText事件按相同逻辑修改:
socket.on("friendRequest", ({ senderId, receiverId }) => {
  // 统一转成字符串类型,和存储的userId类型保持一致,若业务中userId是数字则转Number
  const targetUserId = String(receiverId);
  const receiver = getUser(targetUserId);
  // 查不到用户直接返回,不执行后续推送逻辑
  if (!receiver) {
    console.log(`用户${targetUserId}当前不在线,无有效socket连接`);
    return socket.emit("errorMsg", "对方当前不在线,请求发送失败");
  }
  // 定向推送逻辑
  io.to(receiver.socketId).emit("getFriendRequest", { senderId });
  console.log("匹配到接收用户:", receiver);
});
  1. 检查前端连接逻辑:
    • socket连接建立成功后,必须第一时间触发addUser事件,传入当前登录用户的真实userId,完成上线注册
    • 所有触发推送事件时传入的receiverId,必须和接收方上报的userId值、类型完全一致
  2. 修复模板字符串bug,将启动日志的单引号替换为反引号:
server.listen(PORT,() => console.log(`Server has started on port ${PORT}`));
  1. 优化addUser逻辑,解决同一userId重复映射问题:
const addUser = (userId, socketId) => {
  // 先移除该userId对应的旧连接记录,避免映射错乱
  users = users.filter(user => user.userId !== userId);
  users.push({ userId, socketId });
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 21:33:25