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

Node.js Socket.io聊天应用客户端无法接收服务器消息问题求助

聊天应用Socket.io推送数据接收失败问题

我正在开发一款聊天应用,目前客户端能发送消息,服务器也能接收对应数据,但客户端无法接收Socket.io服务器推送的数据。已搭建独立客户端连接服务器,未接入数据库,尝试多种方法仍未解决,相关代码如下:


SocketServer.js

const io = require('socket.io')(9739, {
cors: {
    origin: "*",
    }
})

let activeUsers = [];

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

   socket.on('login', (data) => {
       console.log(data);
       if (!activeUsers.some((user) => user.id === data)) {
           activeUsers.push({
               id: data,
               socketId: socket.id
           });
       }
       // remove the active user that id is null
       activeUsers = activeUsers.filter((user) => user.id !== null);
       console.log(activeUsers);
       io.emit('activeUsers', activeUsers);
   });

  socket.on("sendMessage",(data)=>{
      const { receiverId } = data;
      const receiver = activeUsers.find((user) => user.id === receiverId);
      console.log("Sending Message to : ", receiver);
      console.log(data);
      if(receiver){
          console.log("comming")
          console.log(receiver.socketId);
          // send message to the receiver
          const RSocketId = receiver.socketId;
          console.log("RSocketId", RSocketId);
          io.to(RSocketId).emit("getMessage", { 
              data: data,
          });
      } 
  });

  socket.on("end", () => {
      console.log("end");
      socket.disconnect();
  });

  socket.on('disconnect', () => {
      console.log('User disconnected');
      activeUsers = activeUsers.filter((user) => user.socketId !== socket.id);
      console.log(activeUsers);
      io.emit('activeUsers', activeUsers);
  });
 });

客户端代码

import axios from "axios";
import React, { useRef } from "react";
import nookies from "nookies";
import Index from "./index";
import FriendsHolder from "../../components/Holders/FriendsHolder";
import FriendsDetails from "../../components/Holders/details-chats-holders/FriendsDetails";
import { useRouter } from "next/router";
import DmsComponent from "../../components/Holders/details-chats-holders/DmsComponent";
import { userDetails } from "../../libs/chats";
import SetUserName from "../../models/SetUserName";
import { io } from "socket.io-client";

const friends = ({ token }: any) => {
  const router = useRouter();

  const [isLoading, setIsLoading] = React.useState(false);

  const [username, setusername] = React.useState(false);

  const [sendMsg, setSendMsg] = React.useState(null);

  const [receivedMsg, setReceivedMsg] = React.useState(null);

  const socket = useRef<any>();

  React.useEffect(() => {
    const init = async () => {
      const { data } = await userDetails(token);
      if (
        data &&
        (data.data.username.length > 20 || data.data.username === "")
      ) {
        setusername(true);
      } else {
        setusername(false);
        socket.current = io("ws://localhost:9739");
        socket?.current.emit("login", data.data?.id);
        socket?.current.on("activeUsers", (users: any) => {
          console.log("active users", users);
        });
      }
    };

    if (token) {
      init();
    }
  }, []);

  const handleLoading = () => {
    setIsLoading(true);
  };

  const handleNotLoading = () => {
    setIsLoading(false);
  };

  React.useEffect(() => {
    handleNotLoading();
  }, [isLoading]);

  // Sending message through the socket server
  React.useEffect(() => {
    if (sendMsg !== null) {
      socket.current?.emit("sendMessage", sendMsg);
    }
  }, [sendMsg]);

  // Recieving Message through the socket server
  React.useEffect(() => {
    socket.current?.on("getMessage", (data: any) => {
      setReceivedMsg(data);
    });
  }, []);

  React.useEffect(() => {
    console.log(receivedMsg);
  }, [receivedMsg]);

  return (
    <Index>
      {username ? (
        <SetUserName />
      ) : (
        <>
          <FriendsHolder data={token} handleLoading={handleLoading} />
          {router.asPath === "/app/friends" && <FriendsDetails token={token} />}
          {router.asPath === `/app/friends?id=${router.query.id}` &&
            !isLoading && (
              <DmsComponent token={token} setSendMsg={setSendMsg} />
            )}
        </>
      )}
    </Index>
  );
};

export default friends;

export const getServerSideProps = async (ctx: any) => {
  const cookies = nookies.get(ctx);
  const token = cookies.token;

  if (!token) {
    return {
      redirect: {
        destination: "/?login",
        permanent: false,
      },
    };
  }
  return {
    props: {
      token: token || null,
    },
  };
};

问题排查与解决

核心问题1:监听时机错误

客户端监听getMessage的useEffect依赖为空数组,组件挂载时就会执行,但此时socket连接还未初始化(init是异步函数,需等待userDetails请求完成才会创建socket)。等socket连接建立后,监听逻辑已经执行过,自然无法捕获后续的推送事件。

修复方案:将getMessage监听逻辑移到socket连接创建后,同时添加组件卸载时的清理逻辑:

React.useEffect(() => {
  const init = async () => {
    const { data } = await userDetails(token);
    if (
      data &&
      (data.data.username.length > 20 || data.data.username === "")
    ) {
      setusername(true);
    } else {
      setusername(false);
      socket.current = io("ws://localhost:9739");
      socket?.current.emit("login", data.data?.id);
      socket?.current.on("activeUsers", (users: any) => {
        console.log("active users", users);
      });
      // 在这里绑定getMessage监听
      socket?.current.on("getMessage", (data: any) => {
        setReceivedMsg(data);
      });
    }
  };

  if (token) {
    init();
  }

  // 组件卸载时清理socket监听与连接
  return () => {
    if (socket.current) {
      socket.current.off("getMessage");
      socket.current.disconnect();
    }
  };
}, []);

核心问题2:未清理监听导致的潜在问题

原代码未在组件卸载时清理socket事件监听和连接,多次挂载组件后可能出现重复监听、连接残留等问题,上述修复方案已包含清理逻辑。

额外验证点

  1. 检查服务器端sendMessage中打印的receiver是否存在,确认目标用户的socketId是否正确;
  2. 可以在socket初始化时添加连接状态监听,验证连接是否正常:
socket.current.on("connect", () => {
  console.log("Socket连接成功");
});
socket.current.on("disconnect", () => {
  console.log("Socket断开连接");
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 04:55:32