React+Node实时聊天应用中Socket.io出现Insufficient resources错误排查
解决Socket.io实时聊天应用的"Insufficient resources"连接错误
一、客户端核心问题:重复创建Socket连接与重复监听事件
你的客户端代码中,const socket = io("http://localhost:5000");直接写在组件函数内部,每次组件重新渲染(比如conv更新时)都会创建一个新的Socket连接,同时useEffect的依赖是conv,每次conv变化都会重新绑定socket.on("output")事件,导致:
- 短时间内创建大量WebSocket连接,耗尽浏览器资源,触发"Insufficient resources"错误
- 重复监听事件,导致消息重复接收或逻辑混乱
客户端修复代码
import React from "react"; import { useState, useEffect, useRef } from "react"; import { io } from "socket.io-client"; const App = () => { const [conv, setConv] = useState([]); const [input, setInput] = useState({ sender: "user", text: "", }); // 使用useRef保存Socket实例,避免重复创建 const socketRef = useRef(null); useEffect(() => { // 只在组件挂载时创建一次Socket连接 socketRef.current = io("http://localhost:5000"); // 绑定output事件监听,仅执行一次 const handleOutput = (data) => { setConv(data[0].messages); }; socketRef.current.on("output", handleOutput); // 组件卸载时清理连接与监听 return () => { socketRef.current.off("output", handleOutput); socketRef.current.disconnect(); }; }, []); // 空依赖,仅在组件挂载/卸载时执行 const handleChange = (e) => { setInput({ sender: "user", text: e.target.value, }); }; const handleSubmit = (e) => { e.preventDefault(); // 使用ref中的Socket实例发送事件 socketRef.current.emit("input", input); // 清空输入框 setInput(prev => ({...prev, text: ""})); }; return ( <div className="App"> <form onSubmit={handleSubmit}> <h1>chat</h1> <div id="messages"> {conv.map((msg, index) => ( <div key={index}> <p> {msg.sender}: {msg.text} </p> </div> ))} </div> <input onChange={handleChange} type="text" value={input.text} /> <input type="submit" /> </form> </div> ); }; export default App;
修复点说明:
- 用
useRef存储Socket实例,确保组件生命周期内仅创建一次连接 - 将Socket初始化与事件监听放在空依赖的
useEffect中,避免重复执行 - 组件卸载时清理事件监听并断开连接,防止内存泄漏
- 给输入框添加
value={input.text},确保受控组件逻辑正确
二、服务端潜在问题:数据更新后未同步客户端+空数据判断缺失
- 数据库更新后未通知客户端:当前服务端在
updateOne后没有主动向客户端发送最新的聊天记录,导致客户端无法实时看到新消息 - 空数组访问风险:
chat.find({ members: { $all: [sender, receiver] } }).toArray返回的res可能为空,此时访问res[0].members会抛出错误,导致服务端异常,影响Socket连接稳定性
服务端修复代码
const express = require("express"); const socketIo = require("socket.io"); const http = require("http"); const PORT = 5000; const app = express(); const server = http.createServer(app); const io = socketIo(server, { cors: { origin: "http://localhost:3000", methods: ["GET", "POST"] // 明确允许的方法,增强安全性 }, }); const MongoClient = require("mongodb").MongoClient; MongoClient.connect("mongodb://localhost:27017", { useUnifiedTopology: true }, (err, client) => { if (err) throw err; console.log("connected to MongoDB"); const database = client.db("local"); const chat = database.collection("chat"); io.on("connection", (socket) => { // 推送初始聊天记录 const sendInitialMessages = async () => { try { const res = await chat.find().toArray(); socket.emit("output", res); } catch (err) { console.error("获取初始消息失败:", err); } }; sendInitialMessages(); // 处理输入事件 socket.on("input", async (input) => { const { sender, text } = input; const receiver = "bot"; try { // 查找对应聊天记录,添加空判断 const res = await chat.find({ members: { $all: [sender, receiver] } }).toArray(); if (res.length === 0) { console.log("未找到对应聊天记录"); return; } const senderInDb = res[0].members[0]; const receiverInDb = res[0].members[1]; if (sender === senderInDb && receiver === receiverInDb) { // 更新数据库 await chat.updateOne( { members: { $all: [sender, receiver] } }, { $push: { messages: { sender, text } } } ); // 更新完成后,重新查询并推送最新消息给所有连接的客户端 const updatedRes = await chat.find().toArray(); io.emit("output", updatedRes); } } catch (err) { console.error("处理输入消息失败:", err); } }); // 客户端断开连接时的清理 socket.on("disconnect", () => { console.log("客户端断开连接:", socket.id); }); }); }); server.listen(PORT, (err) => { if (err) console.log(err); console.log("Server running on Port ", PORT); });
修复点说明:
- 改用
async/await替代回调,代码更清晰且更易处理错误 - 添加
useUnifiedTopology: true参数,适配MongoDB新的连接拓扑 - 在查询聊天记录后添加空数组判断,避免
res[0]报错 - 数据库更新完成后,用
io.emit推送最新消息给所有客户端,实现实时同步 - 添加错误捕获,避免单个请求失败导致服务端崩溃
三、其他注意事项
- 确保MongoDB服务正常运行,且
local数据库下的chat集合存在,且包含members和messages字段的文档 - 浏览器控制台查看是否有其他错误,比如CORS问题(服务端已配置CORS,基本可排除)
- 测试时关闭其他占用大量资源的应用,避免真的因系统资源不足导致连接失败
内容的提问来源于stack exchange,提问作者awfha
相关产品推荐
相关产品推荐

