WebSocket断线后自动重连机制如何实现?重连时旧连接未关闭导致连接爆炸怎么办?
我在开发聊天功能时用WebSocket做实时通信,写了个自动重连逻辑。但发现网络波动时会出现多个连接实例同时存在,服务端返回403错误,控制台提示”WebSocket is already in CLOSING or CLOSED state”。
尝试过用指数退避算法重连,但代码里明明加了close()方法,断开调试时还是能看到多个连接在后台堆积。这是不是因为旧连接没彻底关闭?我的代码逻辑是这样的:
let ws = new WebSocket('wss://chat.example.com');
let retryCount = 0;
function connect() {
ws.onerror = () => ws.close();
ws.onclose = () => {
setTimeout(() => {
ws = new WebSocket('wss://chat.example.com'); // 这里是不是每次重连都新建实例?
retryCount++;
}, 2 ** retryCount * 1000);
};
}
测试时发现当retryCount到3次后,服务端开始拦截新连接,但之前的连接都没被销毁。应该在onclose里加什么判断条件才能确保旧连接完全关闭后再创建新连接呢?
ws.close()并不会立刻关闭连接,而是进入CLOSING状态;另一个是你在onclose里直接新建了 WebSocket 实例,没有确保旧连接彻底销毁。我的血泪教训是,WebSocket 的状态管理一定要严谨,不能盲目依赖
onclose或onerror。以下是我的解决方案:首先,在新建 WebSocket 实例之前,必须确认当前的连接已经彻底关闭。可以用一个标志位来跟踪连接状态,比如
isConnecting,防止重复创建连接。其次,清理掉旧的事件监听器,避免回调函数被多次触发。最后,用指数退避算法控制重连频率是个好思路,但要加上最大重试次数限制,不然服务端会因为过多无效连接直接拒绝。这是我重构后的代码逻辑:
重点来了:
1. 加了一个
isConnecting标志位,防止重复调用connect方法。2. 在
onclose和onerror里都调用了ws.close(),确保进入关闭流程。3. 设置了最大重试次数
maxRetryCount,避免无限重连拖垮服务端。另外,调试时建议你在服务端打印日志,观察每个连接的生命周期。有时候客户端看着像是断开了,但服务端可能还在维持连接,这种情况也会导致连接堆积。
总之,WebSocket 这种长连接的管理真的很头疼,稍不注意就会炸。希望我的经验能帮你少踩点坑。