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事件监听和连接,多次挂载组件后可能出现重复监听、连接残留等问题,上述修复方案已包含清理逻辑。
额外验证点
- 检查服务器端
sendMessage中打印的receiver是否存在,确认目标用户的socketId是否正确; - 可以在socket初始化时添加连接状态监听,验证连接是否正常:
socket.current.on("connect", () => { console.log("Socket连接成功"); }); socket.current.on("disconnect", () => { console.log("Socket断开连接"); });
内容的提问来源于stack exchange,提问作者Kartik Fulara
相关产品推荐
相关产品推荐

