6.9 KiB
6.9 KiB
问题修复 - 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 |
💡 使用建议
立即措施
-
如果使用 Chrome/Edge:
- 将连接池大小改为 10
- 将连接间隔改为 500ms
-
如果使用 Firefox:
- 可以保持连接池大小 20
- 连接间隔保持 300ms
-
如果使用 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() // 重试连接
}
🧪 测试建议
测试步骤
-
调整连接池配置:
- Chrome用户:连接池大小改为10
- 连接间隔改为500ms
-
执行批量任务:
- 选择100个tokens测试
- 观察是否还有连接关闭错误
-
观察控制台:
- 如果还有错误,进一步减小连接池或增加间隔
- 如果正常,可以尝试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 连接管理
- 向后兼容: ✅ 完全兼容