HoRain云--WebSocket心跳检测与断线重连实战
·

🎬 HoRain 云小助手:个人主页
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
目录

实现WebSocket心跳检测和断线重连是构建可靠实时应用的关键。下面我将提供完整的前后端解决方案,涵盖核心机制、错误处理和最佳实践。
📊 核心架构设计
心跳检测机制
// 心跳检测状态机
class HeartbeatState {
constructor() {
this.pingInterval = null; // 发送ping的定时器
this.pongTimeout = null; // 等待pong的超时
this.lastPongTime = null; // 最后一次收到pong的时间
this.pingSent = false; // 是否已发送ping
}
}
🔧 前端完整实现(JavaScript)
1. WebSocket管理器类
class WebSocketManager {
constructor(url, options = {}) {
this.url = url;
this.ws = null;
this.options = {
reconnectInterval: 1000, // 重连间隔
maxReconnectInterval: 30000, // 最大重连间隔
reconnectDecay: 1.5, // 重连间隔增长因子
timeoutInterval: 5000, // 心跳超时时间
pingInterval: 25000, // 心跳间隔
maxReconnectAttempts: Infinity, // 最大重连次数
...options
};
this.reconnectAttempts = 0;
this.reconnectTimer = null;
this.heartbeatTimer = null;
this.pongTimeoutTimer = null;
this.eventHandlers = {
onopen: [],
onclose: [],
onmessage: [],
onerror: [],
onreconnect: []
};
this.init();
}
// 初始化连接
init() {
try {
console.log(`[WebSocket] 正在连接到: ${this.url}`);
this.ws = new WebSocket(this.url);
this.ws.onopen = (event) => this.handleOpen(event);
this.ws.onclose = (event) => this.handleClose(event);
this.ws.onmessage = (event) => this.handleMessage(event);
this.ws.onerror = (event) => this.handleError(event);
} catch (error) {
console.error('[WebSocket] 连接创建失败:', error);
this.scheduleReconnect();
}
}
// 连接打开
handleOpen(event) {
console.log('[WebSocket] 连接已建立');
this.reconnectAttempts = 0;
this.startHeartbeat();
this.triggerEvent('onopen', event);
}
// 连接关闭
handleClose(event) {
console.log(`[WebSocket] 连接关闭,代码: ${event.code}, 原因: ${event.reason}`);
// 清理心跳检测
this.stopHeartbeat();
// 如果不是正常关闭,尝试重连
if (event.code !== 1000 && event.code !== 1001) {
console.log('[WebSocket] 非正常关闭,尝试重连...');
this.scheduleReconnect();
}
this.triggerEvent('onclose', event);
}
// 接收消息
handleMessage(event) {
try {
const data = JSON.parse(event.data);
// 处理心跳响应
if (data.type === 'pong') {
this.handlePong();
return;
}
// 处理业务消息
this.triggerEvent('onmessage', data);
} catch (error) {
console.warn('[WebSocket] 消息解析失败:', error);
}
}
// 错误处理
handleError(event) {
console.error('[WebSocket] 连接错误:', event);
this.triggerEvent('onerror', event);
}
// 启动心跳检测
startHeartbeat() {
this.stopHeartbeat();
this.heartbeatTimer = setInterval(() => {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.sendPing();
}
}, this.options.pingInterval);
}
// 停止心跳检测
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
if (this.pongTimeoutTimer) {
clearTimeout(this.pongTimeoutTimer);
this.pongTimeoutTimer = null;
}
}
// 发送ping
sendPing() {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
const pingData = {
type: 'ping',
timestamp: Date.now()
};
this.ws.send(JSON.stringify(pingData));
console.log('[WebSocket] 发送ping');
// 设置pong超时检测
this.pongTimeoutTimer = setTimeout(() => {
console.warn('[WebSocket] 心跳响应超时,连接可能已断开');
this.handleHeartbeatTimeout();
}, this.options.timeoutInterval);
}
}
// 处理pong响应
handlePong() {
if (this.pongTimeoutTimer) {
clearTimeout(this.pongTimeoutTimer);
this.pongTimeoutTimer = null;
}
console.log('[WebSocket] 收到pong,连接正常');
}
// 心跳超时处理
handleHeartbeatTimeout() {
console.warn('[WebSocket] 心跳检测失败,主动关闭连接');
if (this.ws) {
this.ws.close(1000, '心跳超时');
}
}
// 调度重连
scheduleReconnect() {
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
}
// 检查重连次数限制
if (this.reconnectAttempts >= this.options.maxReconnectAttempts) {
console.error(`[WebSocket] 已达到最大重连次数: ${this.options.maxReconnectAttempts}`);
return;
}
// 计算重连延迟(指数退避)
const delay = Math.min(
this.options.reconnectInterval * Math.pow(this.options.reconnectDecay, this.reconnectAttempts),
this.options.maxReconnectInterval
);
this.reconnectAttempts++;
console.log(`[WebSocket] 将在 ${delay}ms 后尝试第 ${this.reconnectAttempts} 次重连`);
this.reconnectTimer = setTimeout(() => {
console.log(`[WebSocket] 开始第 ${this.reconnectAttempts} 次重连`);
this.triggerEvent('onreconnect', { attempt: this.reconnectAttempts });
this.init();
}, delay);
}
// 发送消息
send(data) {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
if (typeof data !== 'string') {
data = JSON.stringify(data);
}
this.ws.send(data);
return true;
} else {
console.warn('[WebSocket] 连接未就绪,无法发送消息');
return false;
}
}
// 关闭连接
close(code = 1000, reason = '正常关闭') {
console.log('[WebSocket] 主动关闭连接');
this.stopHeartbeat();
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
if (this.ws) {
this.ws.close(code, reason);
}
}
// 事件监听
on(event, handler) {
if (this.eventHandlers[event]) {
this.eventHandlers[event].push(handler);
}
}
// 触发事件
triggerEvent(event, data) {
if (this.eventHandlers[event]) {
this.eventHandlers[event].forEach(handler => {
try {
handler(data);
} catch (error) {
console.error(`[WebSocket] 事件处理器错误: ${event}`, error);
}
});
}
}
// 获取连接状态
getState() {
if (!this.ws) return 'DISCONNECTED';
const states = {
0: 'CONNECTING',
1: 'OPEN',
2: 'CLOSING',
3: 'CLOSED'
};
return states[this.ws.readyState] || 'UNKNOWN';
}
}
2. 使用示例
// 创建WebSocket管理器
const wsManager = new WebSocketManager('wss://api.example.com/ws', {
reconnectInterval: 1000,
maxReconnectInterval: 30000,
reconnectDecay: 1.5,
timeoutInterval: 5000,
pingInterval: 25000,
maxReconnectAttempts: 10
});
// 事件监听
wsManager.on('onopen', (event) => {
console.log('连接已打开');
// 连接成功后发送认证信息
wsManager.send({
type: 'auth',
token: 'your_jwt_token'
});
});
wsManager.on('onmessage', (data) => {
console.log('收到消息:', data);
// 处理业务逻辑
if (data.type === 'notification') {
showNotification(data.content);
}
});
wsManager.on('onclose', (event) => {
console.log('连接关闭');
if (event.code === 1006) {
console.log('网络异常断开');
}
});
wsManager.on('onerror', (error) => {
console.error('连接错误:', error);
});
wsManager.on('onreconnect', (data) => {
console.log(`重连尝试 ${data.attempt}`);
showReconnectStatus(`正在重新连接... (${data.attempt}/10)`);
});
// 发送消息
document.getElementById('sendBtn').addEventListener('click', () => {
const message = {
type: 'chat',
content: document.getElementById('messageInput').value,
timestamp: Date.now()
};
if (wsManager.send(message)) {
console.log('消息发送成功');
} else {
console.log('消息发送失败,已加入发送队列');
// 可以将消息加入队列,等连接恢复后发送
}
});
// 页面可见性变化处理
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// 页面隐藏时,可以减少心跳频率
console.log('页面隐藏,调整心跳频率');
} else {
// 页面显示时,恢复心跳
console.log('页面显示,检查连接状态');
if (wsManager.getState() !== 'OPEN') {
wsManager.scheduleReconnect();
}
}
});
// 网络状态变化处理
window.addEventListener('online', () => {
console.log('网络恢复,尝试重连');
wsManager.scheduleReconnect();
});
window.addEventListener('offline', () => {
console.log('网络断开');
// 可以在这里显示离线提示
});
// 关闭连接
window.addEventListener('beforeunload', () => {
wsManager.close(1000, '页面关闭');
});
🔧 后端实现示例(Node.js + ws库)
1. WebSocket服务器
const WebSocket = require('ws');
const { v4: uuidv4 } = require('uuid');
class WebSocketServer {
constructor(server) {
this.wss = new WebSocket.Server({
server,
clientTracking: true,
perMessageDeflate: false
});
this.clients = new Map(); // 客户端连接映射
this.pingInterval = 30000; // 30秒发送一次ping
this.connectionTimeout = 10000; // 10秒连接超时
this.init();
}
init() {
this.wss.on('connection', (ws, request) => {
this.handleConnection(ws, request);
});
// 定期清理无效连接
setInterval(() => this.cleanupConnections(), 60000);
console.log('WebSocket服务器已启动');
}
handleConnection(ws, request) {
const clientId = uuidv4();
const clientInfo = {
id: clientId,
ws,
ip: request.socket.remoteAddress,
connectedAt: Date.now(),
lastPong: Date.now(),
isAlive: true,
auth: false,
userId: null
};
this.clients.set(clientId, clientInfo);
console.log(`[${clientId}] 新客户端连接,IP: ${clientInfo.ip}`);
// 设置连接超时
const authTimeout = setTimeout(() => {
if (!clientInfo.auth) {
console.log(`[${clientId}] 认证超时,关闭连接`);
ws.close(1008, '认证超时');
}
}, this.connectionTimeout);
// 心跳检测
const heartbeatInterval = setInterval(() => {
if (!clientInfo.isAlive) {
console.log(`[${clientId}] 心跳检测失败,关闭连接`);
ws.terminate();
return;
}
clientInfo.isAlive = false;
this.send(ws, { type: 'ping', timestamp: Date.now() });
}, this.pingInterval);
// 消息处理
ws.on('message', (data) => {
try {
const message = JSON.parse(data);
this.handleMessage(clientId, message, ws);
} catch (error) {
console.error(`[${clientId}] 消息解析错误:`, error);
this.sendError(ws, '消息格式错误');
}
});
// 关闭连接
ws.on('close', (code, reason) => {
clearTimeout(authTimeout);
clearInterval(heartbeatInterval);
this.handleDisconnect(clientId, code, reason);
});
// 错误处理
ws.on('error', (error) => {
console.error(`[${clientId}] 连接错误:`, error);
});
// 发送欢迎消息
this.send(ws, {
type: 'welcome',
clientId,
timestamp: Date.now()
});
}
handleMessage(clientId, message, ws) {
const client = this.clients.get(clientId);
if (!client) return;
console.log(`[${clientId}] 收到消息:`, message.type);
switch (message.type) {
case 'pong':
client.isAlive = true;
client.lastPong = Date.now();
break;
case 'auth':
this.handleAuth(clientId, message, ws);
break;
case 'chat':
this.handleChat(clientId, message, ws);
break;
default:
console.warn(`[${clientId}] 未知消息类型: ${message.type}`);
}
}
handleAuth(clientId, message, ws) {
const client = this.clients.get(clientId);
try {
// 这里应该验证token
const token = message.token;
// 验证逻辑...
client.auth = true;
client.userId = message.userId;
this.send(ws, {
type: 'auth_success',
userId: client.userId
});
console.log(`[${clientId}] 认证成功,用户ID: ${client.userId}`);
} catch (error) {
console.error(`[${clientId}] 认证失败:`, error);
this.sendError(ws, '认证失败');
ws.close(1008, '认证失败');
}
}
handleChat(clientId, message, ws) {
const client = this.clients.get(clientId);
if (!client.auth) {
this.sendError(ws, '未认证');
return;
}
// 广播消息给所有客户端
this.broadcast({
type: 'chat',
from: client.userId,
content: message.content,
timestamp: Date.now()
}, clientId); // 排除发送者
console.log(`[${clientId}] 用户 ${client.userId} 发送了聊天消息`);
}
handleDisconnect(clientId, code, reason) {
const client = this.clients.get(clientId);
if (client) {
console.log(`[${clientId}] 连接关闭,代码: ${code}, 原因: ${reason}`);
// 通知其他用户该用户离线
if (client.auth) {
this.broadcast({
type: 'user_offline',
userId: client.userId,
timestamp: Date.now()
});
}
this.clients.delete(clientId);
}
}
// 发送消息
send(ws, data) {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(data));
}
}
// 发送错误消息
sendError(ws, error) {
this.send(ws, {
type: 'error',
error,
timestamp: Date.now()
});
}
// 广播消息
broadcast(data, excludeClientId = null) {
for (const [clientId, client] of this.clients) {
if (clientId !== excludeClientId && client.auth) {
this.send(client.ws, data);
}
}
}
// 清理无效连接
cleanupConnections() {
const now = Date.now();
const timeout = 60000; // 60秒
for (const [clientId, client] of this.clients) {
if (now - client.lastPong > timeout) {
console.log(`[${clientId}] 连接超时,清理`);
client.ws.terminate();
this.clients.delete(clientId);
}
}
}
// 获取连接统计
getStats() {
return {
total: this.clients.size,
authenticated: Array.from(this.clients.values()).filter(c => c.auth).length,
connections: Array.from(this.clients.values()).map(c => ({
id: c.id,
userId: c.userId,
ip: c.ip,
connectedAt: c.connectedAt,
auth: c.auth
}))
};
}
}
// 使用示例
const http = require('http');
const server = http.createServer();
const wss = new WebSocketServer(server);
server.listen(8080, () => {
console.log('服务器监听在 8080 端口');
});
// 添加管理接口
server.on('request', (req, res) => {
if (req.url === '/admin/stats') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(wss.getStats()));
}
});
🔧 后端实现示例(Spring Boot)
@Component
@ServerEndpoint("/ws")
public class WebSocketEndpoint {
private static final Logger logger = LoggerFactory.getLogger(WebSocketEndpoint.class);
// 存储所有连接
private static final Map<String, Session> sessions = new ConcurrentHashMap<>();
private static final Map<String, UserSession> userSessions = new ConcurrentHashMap<>();
// 心跳超时时间(毫秒)
private static final long HEARTBEAT_TIMEOUT = 30000;
@OnOpen
public void onOpen(Session session) {
String sessionId = session.getId();
sessions.put(sessionId, session);
logger.info("新连接: {}", sessionId);
// 发送欢迎消息
sendMessage(session, new WsMessage("welcome", sessionId));
// 设置心跳检测
setupHeartbeat(session);
}
@OnMessage
public void onMessage(String message, Session session) {
try {
WsMessage wsMessage = JsonUtils.parse(message, WsMessage.class);
switch (wsMessage.getType()) {
case "ping":
handlePing(session);
break;
case "auth":
handleAuth(wsMessage, session);
break;
case "chat":
handleChat(wsMessage, session);
break;
default:
logger.warn("未知消息类型: {}", wsMessage.getType());
}
} catch (Exception e) {
logger.error("消息处理错误", e);
sendError(session, "消息格式错误");
}
}
@OnClose
public void onClose(Session session) {
String sessionId = session.getId();
sessions.remove(sessionId);
UserSession userSession = userSessions.remove(sessionId);
if (userSession != null) {
logger.info("用户断开连接: {}", userSession.getUserId());
// 广播用户离线
broadcast(new WsMessage("user_offline", userSession.getUserId()), sessionId);
}
logger.info("连接关闭: {}", sessionId);
}
@OnError
public void onError(Session session, Throwable error) {
logger.error("WebSocket错误: {}", session.getId(), error);
}
private void handlePing(Session session) {
// 更新心跳时间
UserSession userSession = userSessions.get(session.getId());
if (userSession != null) {
userSession.setLastHeartbeat(System.currentTimeMillis());
}
// 回复pong
sendMessage(session, new WsMessage("pong", null));
}
private void handleAuth(WsMessage message, Session session) {
try {
String token = message.getData().toString();
// 验证token逻辑...
String userId = verifyToken(token);
UserSession userSession = new UserSession();
userSession.setSessionId(session.getId());
userSession.setUserId(userId);
userSession.setLastHeartbeat(System.currentTimeMillis());
userSessions.put(session.getId(), userSession);
logger.info("用户认证成功: {}", userId);
sendMessage(session, new WsMessage("auth_success", userId));
// 广播用户上线
broadcast(new WsMessage("user_online", userId), session.getId());
} catch (Exception e) {
logger.error("认证失败", e);
sendError(session, "认证失败");
try {
session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "认证失败"));
} catch (IOException ex) {
logger.error("关闭连接失败", ex);
}
}
}
private void handleChat(WsMessage message, Session session) {
UserSession userSession = userSessions.get(session.getId());
if (userSession == null) {
sendError(session, "未认证");
return;
}
ChatMessage chatMessage = new ChatMessage();
chatMessage.setFrom(userSession.getUserId());
chatMessage.setContent(message.getData().toString());
chatMessage.setTimestamp(System.currentTimeMillis());
// 广播消息
broadcast(new WsMessage("chat", chatMessage), session.getId());
}
private void sendMessage(Session session, WsMessage message) {
if (session.isOpen()) {
try {
session.getBasicRemote().sendText(JsonUtils.stringify(message));
} catch (IOException e) {
logger.error("发送消息失败", e);
}
}
}
private void broadcast(WsMessage message, String excludeSessionId) {
String messageJson = JsonUtils.stringify(message);
sessions.forEach((sessionId, session) -> {
if (!sessionId.equals(excludeSessionId) && session.isOpen()) {
try {
session.getBasicRemote().sendText(messageJson);
} catch (IOException e) {
logger.error("广播消息失败", e);
}
}
});
}
private void sendError(Session session, String error) {
sendMessage(session, new WsMessage("error", error));
}
private void setupHeartbeat(Session session) {
// 定时检查心跳
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(() -> {
UserSession userSession = userSessions.get(session.getId());
if (userSession != null) {
long now = System.currentTimeMillis();
if (now - userSession.getLastHeartbeat() > HEARTBEAT_TIMEOUT) {
logger.warn("心跳超时,关闭连接: {}", userSession.getUserId());
try {
session.close();
} catch (IOException e) {
logger.error("关闭连接失败", e);
}
}
}
}, 0, 30, TimeUnit.SECONDS);
}
// 管理接口
public static Map<String, Object> getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalConnections", sessions.size());
stats.put("authenticatedUsers", userSessions.size());
return stats;
}
}
⚡ 性能优化与最佳实践
1. 网络优化策略
// 自适应心跳间隔
class AdaptiveHeartbeat {
constructor() {
this.baseInterval = 30000; // 基础间隔
this.maxInterval = 120000; // 最大间隔
this.minInterval = 5000; // 最小间隔
this.currentInterval = this.baseInterval;
this.networkQuality = 1.0; // 网络质量因子
}
// 根据网络状况调整心跳间隔
adjustInterval(latency) {
if (latency < 100) {
// 网络良好,可以适当延长心跳间隔
this.networkQuality = Math.min(1.2, this.networkQuality * 1.1);
} else if (latency > 1000) {
// 网络较差,缩短心跳间隔
this.networkQuality = Math.max(0.5, this.networkQuality * 0.9);
}
this.currentInterval = Math.max(
this.minInterval,
Math.min(
this.maxInterval,
this.baseInterval * this.networkQuality
)
);
return this.currentInterval;
}
}
2. 消息队列和重发机制
class MessageQueue {
constructor(wsManager) {
this.queue = [];
this.maxSize = 100;
this.wsManager = wsManager;
}
// 添加消息到队列
add(message) {
if (this.queue.length >= this.maxSize) {
this.queue.shift(); // 移除最旧的消息
}
const messageWithId = {
...message,
id: Date.now() + '_' + Math.random().toString(36).substr(2, 9),
timestamp: Date.now(),
retryCount: 0,
maxRetries: 3
};
this.queue.push(messageWithId);
this.trySend();
}
// 尝试发送队列中的消息
trySend() {
if (this.wsManager.getState() !== 'OPEN') {
return;
}
const now = Date.now();
for (let i = 0; i < this.queue.length; i++) {
const message = this.queue[i];
// 检查重试次数
if (message.retryCount >= message.maxRetries) {
this.queue.splice(i, 1);
i--;
console.warn(`消息 ${message.id} 达到最大重试次数,已丢弃`);
continue;
}
// 检查消息是否过期(30秒)
if (now - message.timestamp > 30000) {
this.queue.splice(i, 1);
i--;
console.warn(`消息 ${message.id} 已过期,已丢弃`);
continue;
}
// 尝试发送
if (this.wsManager.send(message)) {
this.queue.splice(i, 1);
i--;
console.log(`消息 ${message.id} 发送成功`);
} else {
message.retryCount++;
message.lastRetry = now;
console.log(`消息 ${message.id} 发送失败,重试次数: ${message.retryCount}`);
}
}
}
}
3. 连接质量监控
class ConnectionMonitor {
constructor(wsManager) {
this.wsManager = wsManager;
this.metrics = {
latency: [],
packetLoss: 0,
reconnectCount: 0,
totalBytesSent: 0,
totalBytesReceived: 0
};
this.startMonitoring();
}
startMonitoring() {
// 监控网络延迟
setInterval(() => {
this.measureLatency();
}, 30000);
// 监控连接状态
this.wsManager.on('onreconnect', () => {
this.metrics.reconnectCount++;
});
}
measureLatency() {
const startTime = Date.now();
this.wsManager.send({
type: 'ping',
timestamp: startTime
});
// 假设我们有机制记录往返时间
}
getConnectionQuality() {
const recentLatency = this.metrics.latency.slice(-10);
const avgLatency = recentLatency.length > 0
? recentLatency.reduce((a, b) => a + b, 0) / recentLatency.length
: 0;
if (avgLatency < 100) return 'excellent';
if (avgLatency < 300) return 'good';
if (avgLatency < 1000) return 'fair';
return 'poor';
}
}
🚨 错误处理与恢复
1. 错误分类处理
class ErrorHandler {
static handleWebSocketError(error, wsManager) {
switch (error.code) {
case 1000:
console.log('正常关闭');
break;
case 1006:
console.log('连接异常断开');
wsManager.scheduleReconnect();
break;
case 1008:
console.log('认证失败,需要重新登录');
this.handleAuthenticationFailure();
break;
case 1011:
console.log('服务器内部错误');
wsManager.scheduleReconnect();
break;
case 1012:
console.log('服务重启');
setTimeout(() => wsManager.scheduleReconnect(), 5000);
break;
default:
console.warn('未知错误代码:', error.code);
wsManager.scheduleReconnect();
}
}
static handleAuthenticationFailure() {
// 清除本地token
localStorage.removeItem('auth_token');
// 跳转到登录页
window.location.href = '/login';
}
}
2. 降级策略
class FallbackStrategy {
constructor(url) {
this.url = url;
this.fallbackMode = false;
this.pollingInterval = null;
}
// 切换到轮询模式
enablePolling() {
console.log('WebSocket不可用,切换到轮询模式');
this.fallbackMode = true;
this.pollingInterval = setInterval(() => {
this.poll();
}, 5000); // 每5秒轮询一次
}
// 禁用轮询,恢复WebSocket
disablePolling() {
console.log('恢复WebSocket连接');
this.fallbackMode = false;
if (this.pollingInterval) {
clearInterval(this.pollingInterval);
this.pollingInterval = null;
}
}
async poll() {
try {
const response = await fetch(`${this.url}/poll`);
const data = await response.json();
// 处理轮询返回的数据
this.handlePollData(data);
} catch (error) {
console.error('轮询失败:', error);
}
}
handlePollData(data) {
// 处理轮询数据
}
}
💎 最佳实践总结
1. 心跳检测配置建议
|
场景 |
心跳间隔 |
超时时间 |
重连策略 |
|---|---|---|---|
|
实时聊天 |
20-30秒 |
5-10秒 |
立即重连,指数退避 |
|
股票行情 |
10-15秒 |
3-5秒 |
立即重连,固定间隔 |
|
IoT设备 |
60-120秒 |
30秒 |
指数退避,最大重试10次 |
|
游戏 |
5-10秒 |
2-3秒 |
立即重连,无退避 |
2. 安全考虑
// 1. 认证机制
const authPayload = {
type: 'auth',
token: getJWTToken(),
timestamp: Date.now(),
sign: generateSignature() // 防止重放攻击
};
// 2. 消息加密
function encryptMessage(message, secretKey) {
// 使用AES加密消息体
return CryptoJS.AES.encrypt(
JSON.stringify(message),
secretKey
).toString();
}
// 3. 频率限制
class RateLimiter {
constructor(maxMessages, timeWindow) {
this.messageCount = 0;
this.lastReset = Date.now();
this.maxMessages = maxMessages;
this.timeWindow = timeWindow;
}
checkLimit() {
const now = Date.now();
// 重置计数器
if (now - this.lastReset > this.timeWindow) {
this.messageCount = 0;
this.lastReset = now;
}
if (this.messageCount >= this.maxMessages) {
return false;
}
this.messageCount++;
return true;
}
}
3. 监控和日志
// 集成Sentry等监控工具
class WebSocketMonitor {
constructor(wsManager) {
this.wsManager = wsManager;
this.setupMonitoring();
}
setupMonitoring() {
this.wsManager.on('onopen', () => {
Sentry.captureMessage('WebSocket连接成功', 'info');
});
this.wsManager.on('onclose', (event) => {
Sentry.captureMessage(`WebSocket连接关闭: ${event.code}`, 'warning');
});
this.wsManager.on('onreconnect', (data) => {
if (data.attempt > 5) {
Sentry.captureMessage(`WebSocket重连次数过多: ${data.attempt}`, 'error');
}
});
}
}
4. 测试策略
// 连接稳定性测试
class ConnectionTester {
async testConnection(url, duration = 60000) {
const results = {
totalTests: 0,
successful: 0,
failed: 0,
avgLatency: 0,
maxLatency: 0
};
const startTime = Date.now();
while (Date.now() - startTime < duration) {
try {
const latency = await this.ping(url);
results.totalTests++;
results.successful++;
results.avgLatency = (results.avgLatency + latency) / results.totalTests;
results.maxLatency = Math.max(results.maxLatency, latency);
} catch (error) {
results.totalTests++;
results.failed++;
}
await this.delay(1000);
}
return results;
}
async ping(url) {
return new Promise((resolve, reject) => {
const start = Date.now();
const ws = new WebSocket(url);
ws.onopen = () => {
const latency = Date.now() - start;
ws.close();
resolve(latency);
};
ws.onerror = () => {
reject(new Error('连接失败'));
};
setTimeout(() => {
reject(new Error('连接超时'));
}, 5000);
});
}
}
通过实现完整的心跳检测和断线重连机制,可以显著提升WebSocket应用的稳定性和用户体验。关键是要根据具体业务场景调整参数,并配合完善的监控和错误处理。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙
更多推荐




所有评论(0)