乐闻世界logo
搜索文章和话题

WebSocket如何实现断线重连?

2月18日 22:08

WebSocket断线重连机制详解

WebSocket连接可能会因为网络波动、服务器重启、超时等原因断开,实现可靠的断线重连机制至关重要。

连接状态检测

WebSocket有四种连接状态:

javascript
const ws = new WebSocket('ws://example.com'); // 0: CONNECTING - 正在连接 // 1: OPEN - 已连接 // 2: CLOSING - 正在关闭 // 3: CLOSED - 已关闭 console.log(ws.readyState); // 获取当前状态

基础重连实现

javascript
class WebSocketManager { constructor(url) { this.url = url; this.ws = null; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; this.reconnectInterval = 3000; // 3秒 this.shouldReconnect = true; this.connect(); } connect() { this.ws = new WebSocket(this.url); this.ws.onopen = () => { console.log('WebSocket连接已建立'); this.reconnectAttempts = 0; }; this.ws.onclose = (event) => { console.log('WebSocket连接已关闭:', event.code, event.reason); if (this.shouldReconnect) { this.reconnect(); } }; this.ws.onerror = (error) => { console.error('WebSocket错误:', error); }; } reconnect() { if (this.reconnectAttempts >= this.maxReconnectAttempts) { console.error('达到最大重连次数,停止重连'); return; } this.reconnectAttempts++; const delay = this.getReconnectDelay(); console.log(`${delay}ms后尝试第${this.reconnectAttempts}次重连`); setTimeout(() => { this.connect(); }, delay); } getReconnectDelay() { // 指数退避策略 return Math.min( this.reconnectInterval * Math.pow(2, this.reconnectAttempts - 1), 30000 // 最大30秒 ); } disconnect() { this.shouldReconnect = false; if (this.ws) { this.ws.close(); } } } // 使用示例 const wsManager = new WebSocketManager('ws://example.com/socket');

优雅关闭处理

javascript
class WebSocketManager { // ... 其他代码 close(code = 1000, reason = 'Normal closure') { this.shouldReconnect = false; if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.ws.close(code, reason); } } // 在onclose中判断是否为正常关闭 ws.onclose = (event) => { // 正常关闭状态码:1000 if (event.code === 1000) { console.log('正常关闭连接'); return; } // 异常关闭,尝试重连 if (this.shouldReconnect) { this.reconnect(); } }; }

常见关闭状态码

状态码含义
1000正常关闭
1001端点离开
1002协议错误
1003不支持的数据类型
1005无状态码(内部使用)
1006连接异常关闭
1007数据类型不一致
1008策略违规
1009消息过大
1010缺少扩展
1011内部错误
1015TLS握手失败

心跳检测与重连

javascript
class WebSocketManager { constructor(url) { // ... 其他初始化 this.heartbeatInterval = 30000; // 30秒 this.heartbeatTimer = null; this.pongTimeout = 5000; // 5秒超时 this.pongTimer = null; } startHeartbeat() { this.heartbeatTimer = setInterval(() => { if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.sendPing(); } }, this.heartbeatInterval); } sendPing() { this.ws.send(JSON.stringify({ type: 'ping' })); // 设置pong超时 this.pongTimer = setTimeout(() => { console.error('心跳超时,关闭连接'); this.ws.close(); }, this.pongTimeout); } handlePong() { if (this.pongTimer) { clearTimeout(this.pongTimer); this.pongTimer = null; } } ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'pong') { this.handlePong(); } // 处理其他消息... }; ws.onopen = () => { this.startHeartbeat(); }; ws.onclose = () => { this.stopHeartbeat(); }; stopHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; } if (this.pongTimer) { clearTimeout(this.pongTimer); this.pongTimer = null; } } }

离线检测

javascript
class WebSocketManager { constructor(url) { // ... 其他初始化 this.setupOfflineDetection(); } setupOfflineDetection() { window.addEventListener('online', () => { console.log('网络已恢复,尝试重连'); if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { this.connect(); } }); window.addEventListener('offline', () => { console.log('网络已断开'); }); } }

最佳实践

  1. 指数退避:重连间隔逐渐增加,避免服务器压力
  2. 最大重连次数:防止无限重连
  3. 心跳机制:及时检测连接状态
  4. 优雅关闭:区分正常和异常关闭
  5. 离线检测:监听网络状态变化
  6. 状态通知:向用户反馈连接状态
  7. 消息队列:重连期间缓存消息,连接成功后发送
标签:WebSocket