Files
xyzw_web_helper/MD说明文件夹/问题修复-WebSocket连接关闭错误v3.13.5.2.md
2025-10-17 20:56:50 +08:00

6.9 KiB
Raw Permalink Blame History

问题修复 - WebSocket连接关闭错误 v3.13.5.2

📋 问题描述

错误信息

WebSocket connection to 'wss://...' failed: 
WebSocket is closed before the connection is established.

错误含义

WebSocket 连接在握手完成之前就被关闭了。这是一个浏览器或网络层面的错误,不是应用层错误。


🔍 问题分析

主要原因

1. 浏览器并发WebSocket连接限制 🔴

原因:

  • 大多数浏览器对同一域名的 WebSocket 并发连接有限制
  • Chrome/Edge: 通常限制为 6-10个
  • Firefox: 通常限制为 200个(但建立速度有限制)
  • Safari: 通常限制为 6个

您的场景:

  • 900+ tokens 批量任务
  • 连接池大小: 20可能接近或超过某些浏览器限制
  • 当连接池快速创建连接时,浏览器可能拒绝部分连接

2. 空闲超时设置过短 🟡

原因:

  • 默认空闲超时: 30秒
  • 批量任务可能需要更长时间执行
  • 连接在任务完成前就被空闲超时关闭

修复:

// ❌ 旧代码:缺少 idleTimeout 配置
const wsClient = new XyzwWebSocketClient({
    url: finalWsUrl,
    utils: g_utils,
    heartbeatMs: 3000
})

// ✅ 新代码设置5分钟空闲超时
const wsClient = new XyzwWebSocketClient({
    url: finalWsUrl,
    utils: g_utils,
    heartbeatMs: 3000,
    idleTimeout: 5 * 60 * 1000  // 5分钟
})

3. 连接建立速度过快 🟡

原因:

  • 连接池在短时间内创建多个连接
  • 浏览器或服务器可能有速率限制
  • 默认连接间隔: 300ms可能太短

🔧 修复方案

修复 1: 延长空闲超时时间

文件: src/stores/tokenStore.js

修改:

idleTimeout: 5 * 60 * 1000  // 从30秒延长到5分钟

效果:

  • 连接不会因为任务执行时间长而被关闭
  • 给批量任务足够的执行时间

修复 2: 优化连接池配置 ⚠️

建议配置:

对于 Chrome/Edge 用户:

// 连接池配置(在批量任务页面)
连接池大小: 10减少到浏览器限制以下
连接间隔: 500ms增加间隔避免建立过快
同时执行数: 5保持不变

对于 Firefox 用户:

// Firefox 连接限制较高,可以使用更大的连接池
连接池大小: 20保持默认
连接间隔: 300ms保持默认
同时执行数: 5保持不变

修复 3: 检查浏览器类型并推荐配置 💡

在应用中添加浏览器检测和提示:

// 检测浏览器类型
const isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor)
const isFirefox = /Firefox/.test(navigator.userAgent)

if (isChrome && poolSize > 10) {
  console.warn('⚠️ Chrome浏览器建议连接池大小不超过10当前设置: ' + poolSize)
  console.warn('💡 建议修改为10以避免连接被拒绝')
}

📊 不同浏览器的限制

浏览器 WebSocket并发限制 建议连接池大小 建议连接间隔
Chrome/Edge 6-10个 ≤10 500ms
Firefox ~200个 20-50 300ms
Safari ~6个 ≤6 500ms
Opera ~10个 ≤10 500ms

💡 使用建议

立即措施

  1. 如果使用 Chrome/Edge

    • 将连接池大小改为 10
    • 将连接间隔改为 500ms
  2. 如果使用 Firefox

    • 可以保持连接池大小 20
    • 连接间隔保持 300ms
  3. 如果使用 Safari

    • 将连接池大小改为 6
    • 将连接间隔改为 500ms

长期方案

方案A: 动态调整连接池大小(推荐)

// 根据浏览器自动调整
const getOptimalPoolSize = () => {
  const ua = navigator.userAgent
  if (/Safari/.test(ua) && !/Chrome/.test(ua)) return 6  // Safari
  if (/Firefox/.test(ua)) return 20  // Firefox
  if (/Chrome|Edge/.test(ua)) return 10  // Chrome/Edge
  return 10  // 默认
}

方案B: 使用更保守的配置

// 适用于所有浏览器的保守配置
连接池大小: 8
连接间隔: 500ms
同时执行数: 4

方案C: 增加重试机制

// 如果连接失败,等待后重试
if (error.message.includes('closed before the connection is established')) {
  await sleep(1000)  // 等待1秒
  retry()  // 重试连接
}

🧪 测试建议

测试步骤

  1. 调整连接池配置:

    • Chrome用户连接池大小改为10
    • 连接间隔改为500ms
  2. 执行批量任务:

    • 选择100个tokens测试
    • 观察是否还有连接关闭错误
  3. 观察控制台:

    • 如果还有错误,进一步减小连接池或增加间隔
    • 如果正常可以尝试200、500、900个tokens

预期结果

  • 不再出现 "closed before the connection is established" 错误
  • 连接成功率提升
  • 任务执行稳定

🔄 回退方案

如果修改后仍有问题,可以:

方案1: 禁用空闲超时

idleTimeout: 0  // 禁用空闲超时

方案2: 使用极保守配置

连接池大小: 5
连接间隔: 1000ms (1)
同时执行数: 3

方案3: 分批执行

// 将900个tokens分成多批执行
// 每批100个执行完一批再执行下一批

📝 技术说明

WebSocket连接生命周期

1. new WebSocket(url)       ← 创建连接对象
2. 握手过程                 ← 浏览器与服务器协商
3. onopen 事件              ← 连接建立成功
4. 可以发送/接收消息
5. onclose 事件             ← 连接关闭

错误发生在步骤2

  • 握手过程中,浏览器决定拒绝或关闭连接
  • 通常是因为达到并发限制或资源不足

为什么不同浏览器限制不同?

  • Chrome/Safari 为了节省资源,限制较严格
  • Firefox 对 WebSocket 限制较宽松,但有其他性能限制
  • 服务器端: 也可能有连接数限制

📌 总结

已实施的修复

  • 延长空闲超时从30秒到5分钟
  • 添加 idleTimeout 配置到 WebSocket 客户端创建

需要用户操作 ⚠️

  • 根据浏览器类型调整连接池大小
  • 如果使用 Chrome/Edge建议改为10
  • 如果使用 Safari建议改为6
  • 测试并观察效果

后续优化方向 💡

  • 添加浏览器检测和自动配置
  • 添加连接失败重试机制
  • 添加配置建议提示

🎯 版本信息

  • 版本号: v3.13.5.2
  • 修复类型: 性能优化 + 配置调整
  • 影响范围: WebSocket 连接管理
  • 向后兼容: 完全兼容

📚 相关文档