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

页面刷新后恢复Socket.IO连接及任务日志同步问题求助

解决方案

核心问题分析

页面刷新会销毁旧Socket连接并创建新实例,导致新连接无法获取之前的任务日志;Connection State Recovery未生效大概率是配置不完整或仅依赖该机制无法覆盖所有场景(比如刷新超过恢复时长)。下面是两种互补的解决思路:


1. 服务器端维护全局任务日志队列(最可靠方案)

在服务器端存储所有任务日志,新Socket连接建立后主动推送历史日志,确保刷新页面后能补全之前的日志记录。

服务器端(server.js)修改:

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');

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

// 启用连接状态恢复(可选,搭配全局日志使用)
const io = new Server(server, {
  connectionStateRecovery: {
    maxDisconnectionDuration: 120000, // 2分钟内重连可恢复状态
    skipMiddlewares: true
  }
});

// 全局存储所有任务日志
const taskLogs = [];

io.on('connection', (socket) => {
  // 新连接建立后立即推送历史日志
  socket.emit('sync-history', taskLogs);

  // 处理任务启动请求
  socket.on('start-task', (taskData) => {
    const log = `[${new Date().toLocaleString()}] 任务 "${taskData.name}" 启动 | 重复时长: ${taskData.interval}ms | 停止时长: ${taskData.stopDuration}ms`;
    console.log(log);
    taskLogs.push(log);
    // 广播给所有在线客户端(包括当前连接)
    io.emit('task-log', log);
  });

  // 处理任务完成日志
  socket.on('task-complete', (taskName) => {
    const log = `[${new Date().toLocaleString()}] 任务 "${taskName}" 完成`;
    console.log(log);
    taskLogs.push(log);
    io.emit('task-log', log);
  });

  socket.on('disconnect', () => {
    console.log(`客户端 ${socket.id} 断开连接`);
  });
});

app.use(express.static(__dirname));
server.listen(3000, () => console.log('服务器运行在 http://localhost:3000'));

客户端(index.html)修改:

<!DOCTYPE html>
<html>
<head>
  <title>任务调度系统</title>
  <script src="/socket.io/socket.io.js"></script>
</head>
<body>
  <input type="text" id="taskName" placeholder="输入任务名称">
  <input type="number" id="interval" placeholder="重复时长(ms)" min="1000">
  <input type="number" id="stopDuration" placeholder="停止时长(ms)" min="1000">
  <button onclick="submitTask()">启动任务</button>

  <script>
    // 初始化Socket并启用连接状态恢复
    const socket = io({ connectionStateRecovery: {} });

    // 同步历史日志到客户端控制台
    socket.on('sync-history', (logs) => {
      logs.forEach(log => console.log(log));
    });

    // 接收实时任务日志
    socket.on('task-log', (log) => {
      console.log(log);
    });

    function submitTask() {
      const taskName = document.getElementById('taskName').value.trim();
      const interval = parseInt(document.getElementById('interval').value);
      const stopDuration = parseInt(document.getElementById('stopDuration').value);
      
      if (!taskName || isNaN(interval) || isNaN(stopDuration)) return alert('请填写完整有效参数');
      
      socket.emit('start-task', { name: taskName, interval, stopDuration });
    }
  </script>
</body>
</html>

2. 修复Connection State Recovery配置

如果要依赖官方的重连恢复机制,需确保服务器和客户端都正确配置,且关键事件支持恢复:

  • 服务器端必须在初始化Server时开启connectionStateRecovery
  • 客户端初始化io时也要传入connectionStateRecovery: {}
  • 对于自定义事件(如start-task),需在服务器端标记为可恢复(通过socket.recover()或配置ackTimeout)

不过该机制仅适用于短时间内的重连(默认1分钟),若用户刷新页面后间隔较久再操作,还是会丢失日志,因此推荐搭配全局日志队列使用。


关键注意事项

  • 用io.emit()代替socket.emit()广播日志:确保所有在线客户端(包括刷新后的新连接)都能收到实时日志
  • 全局日志可按需做持久化(比如存文件或数据库),避免服务器重启后丢失日志
  • 若任务是服务器端调度运行的,需确保任务逻辑不依赖单个Socket连接,而是独立运行,再将日志广播给所有客户端

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 22:20:36