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

Socket.io客户端连接后立即断开问题排查求助

Socket.io 连接异常问题分析与解决

问题现象

  • 服务器重启后客户端无法连接;刷新页面后客户端短暂连接随即立刻断开
  • Firefox/Chrome/Safari均出现相同问题,此前针对WebSocket连接失败的方案无效
  • 编辑保存客户端代码时Socket.io可正常连接,但刷新页面会触发「断开-连接-断开」的循环

客户端代码

const socket = io.connect("http://localhost:8000");
React.useEffect(() => {
    fetch("http://localhost:8000/")
      .then((res) => res.json())
      .then((data) => setData(data.message));
  }, []);

  useEffect(() => {
    socket.on("FromAPI", data => {
      setTime(data);
    });
    socket.on("connect", data => {
      setTime(data);
      console.log('socket connected');
      console.log(socket.id)
    })
    socket.on("reconnect_failed", () => {
      console.log(socket.disconnected)
    });
    return () =>
      socket.disconnect();
  }, [])

服务端代码

const io = require('socket.io')(http, {
    cors: {
        origin: "http://localhost:3000"
    }
});

let interval;
let socket_id;
io.on("connection", (socket) => {
    socket_id = socket.id;
    console.log(socket.id, "connected");
    if (interval) {
        clearInterval(interval);
    }
    interval = setInterval(() => getApiAndEmit(socket), 1000);
    socket.on("joingame", (data) => {
        console.log("connected to game");
        // too many connecting in terminal logs
    })
    socket.on("disconnect", () => {
        if (cd_current != "" && gd_current != "") {
            sql_db.handleDisconnect(cd_current, gd_current, socket_id);
        }
        console.log(cd_current);
        console.log(`Client ${socket_id} disconnected`);
        clearInterval(interval);
    });
});

问题根源与修复方案

1. 客户端:全局Socket实例重复断开问题

客户端通过io.connect创建的是全局Socket实例,组件卸载时执行的return () => socket.disconnect()会直接断开这个全局实例。页面刷新时,组件重新挂载前会触发上一次的清理函数,导致刚创建的新连接被立刻断开。

修复:
清理时仅移除当前组件绑定的事件监听,而非断开全局连接;或者在useEffect内部创建Socket实例,避免全局污染:

useEffect(() => {
    // 单独声明事件处理函数,方便后续移除监听
    const handleFromAPI = data => setTime(data);
    const handleConnect = data => {
      setTime(data);
      console.log('socket connected');
      console.log(socket.id)
    };
    const handleReconnectFailed = () => console.log(socket.disconnected);

    socket.on("FromAPI", handleFromAPI);
    socket.on("connect", handleConnect);
    socket.on("reconnect_failed", handleReconnectFailed);

    // 清理阶段只移除事件监听,保留连接让Socket.io自动处理重连
    return () => {
      socket.off("FromAPI", handleFromAPI);
      socket.off("connect", handleConnect);
      socket.off("reconnect_failed", handleReconnectFailed);
    };
}, [])

2. 服务端:全局变量导致多客户端冲突

服务端使用全局的interval和socket_id变量,当多个客户端连接时,新连接会覆盖这些变量,导致旧客户端的定时器被清除,断开时还会使用错误的socket_id执行数据库操作。

修复:
将变量改为每个Socket连接的局部变量,确保每个客户端拥有独立的资源:

io.on("connection", (socket) => {
    const socket_id = socket.id; // 改为局部变量
    console.log(socket_id, "connected");
    let interval; // 改为局部变量
    interval = setInterval(() => getApiAndEmit(socket), 1000);
    
    socket.on("joingame", (data) => {
        console.log("connected to game");
    })
    
    socket.on("disconnect", () => {
        if (cd_current != "" && gd_current != "") {
            sql_db.handleDisconnect(cd_current, gd_current, socket_id);
        }
        console.log(cd_current);
        console.log(`Client ${socket_id} disconnected`);
        clearInterval(interval);
    });
});

3. 额外优化项

  • 完善CORS配置,添加credentials: true确保跨域认证正常:
    const io = require('socket.io')(http, {
        cors: {
            origin: "http://localhost:3000",
            credentials: true
        }
    });
    
  • 客户端连接时强制使用WebSocket传输,避免轮询带来的异常:
    const socket = io.connect("http://localhost:8000", {
        transports: ['websocket']
    });
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 22:23:32