【IM】如何封装一个好用的功能全面的 WebSocket
客户端类?
直接上代码:
class WebSocketClient {
constructor(url, options = {}) {
this.url = url;
this.ws = null;
this.reconnectInterval = options.reconnectInterval || 5000; // 初始重连间隔时间(毫秒)
this.maxReconnectInterval = options.maxReconnectInterval || 60000; // 最大重连间隔时间(毫秒)
this.heartbeatInterval = options.heartbeatInterval || 30000; // 心跳间隔时间(毫秒)
this.heartbeatTimeout = options.heartbeatTimeout || 10000; // 心跳超时时间(毫秒)
this.maxReconnectAttempts = options.maxReconnectAttempts || 5; // 最大重连次数
this.maxHeartbeatTimeouts = options.maxHeartbeatTimeouts || 3; // 最大心跳超时次数
this.heartbeatTimer = null;
this.reconnectTimer = null;
this.isReconnecting = false;
this.reconnectAttempts = 0;
this.heartbeatTimeoutCount = 0; // 心跳超时计数器
this.messageQueue = [];
this.onOpen = options.onOpen || (() => {});
this.onMessage = options.onMessage || (() => {});
this.onClose = options.onClose || (() => {});
this.onError = options.onError || (() => {});
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log("WebSocket 连接已打开");
this.isReconnecting = false;
this.reconnectAttempts = 0;
this.heartbeatTimeoutCount = 0; // 重置心跳超时计数器
this.startHeartbeat();
this.flushMessageQueue();
this.onOpen();
};
this.ws.onmessage = (event) => {
console.log("收到消息:", event.data);
if (event.data === JSON.stringify({ type: "heartbeat" })) {
this.resetHeartbeatTimeout();
}
this.onMessage(event);
};
this.ws.onclose = (event) => {
console.log("WebSocket 连接已关闭", event.code, event.reason);
this.stopHeartbeat();
this.onClose(event);
if (
!this.isReconnecting &&
event.code !== 1000 &&
event.code !== 1001 &&
this.reconnectAttempts < this.maxReconnectAttempts
) {
this.reconnect();
}
};
this.ws.onerror = (error) => {
console.error("WebSocket 错误:", error);
this.onError(error);
};
}
startHeartbeat() {
this.heartbeatTimer = setInterval(() => {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type: "heartbeat" }));
this.setHeartbeatTimeout();
}
}, this.heartbeatInterval);
}
stopHeartbeat() {
clearInterval(this.heartbeatTimer);
clearTimeout(this.heartbeatTimeoutId);
}
setHeartbeatTimeout() {
clearTimeout(this.heartbeatTimeoutId);
this.heartbeatTimeoutId = setTimeout(() => {
console.log("心跳超时,增加超时计数器");
this.heartbeatTimeoutCount++;
if (this.heartbeatTimeoutCount >= this.maxHeartbeatTimeouts) {
console.log("达到最大心跳超时次数,尝试重新连接");
this.ws.close();
} else {
this.setHeartbeatTimeout(); // 重新设置超时定时器
}
}, this.heartbeatTimeout);
}
resetHeartbeatTimeout() {
this.heartbeatTimeoutCount = 0; // 重置心跳超时计数器
this.setHeartbeatTimeout();
}
reconnect() {
this.isReconnecting = true;
const interval = Math.min(
this.reconnectInterval * Math.pow(2, this.reconnectAttempts),
this.maxReconnectInterval
);
this.reconnectTimer = setTimeout(() => {
console.log(`尝试重新连接...(第 ${this.reconnectAttempts + 1} 次)`);
this.reconnectAttempts++;
this.connect();
}, interval);
}
send(data) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
} else {
this.messageQueue.push(data);
}
}
flushMessageQueue() {
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift();
this.ws.send(JSON.stringify(message));
}
}
close() {
this.ws.close(1000, "手动关闭");
this.stopHeartbeat();
clearTimeout(this.reconnectTimer);
}
}
// 使用示例
const wsClient = new WebSocketClient("ws://example.com/socket", {
onOpen: () => console.log("连接已打开"),
onMessage: (event) => console.log("收到消息:", event.data),
onClose: (event) => console.log("连接已关闭", event.code, event.reason),
onError: (error) => console.error("连接错误:", error),
});
// 发送消息
wsClient.send({ type: "message", content: "Hello, Server!" });
// 关闭连接
// wsClient.close();
这个文件 ws.js
实现了一个功能完善的 WebSocket 客户端类 WebSocketClient
,支持心跳机制、断线重连和心跳超时重连等功能。以下是该文件的主要功能描述:
主要功能
-
WebSocket 连接管理:
- 连接建立:通过
connect
方法建立 WebSocket 连接。 - 连接打开:在
ws.onopen
事件中处理连接打开后的逻辑,包括启动心跳机制和发送缓存的消息。 - 连接关闭:在
ws.onclose
事件中处理连接关闭后的逻辑,包括根据关闭代码决定是否进行重连。 - 连接错误:在
ws.onerror
事件中处理连接错误,并记录错误信息。
- 连接建立:通过
-
心跳机制:
- 发送心跳:通过
startHeartbeat
方法定期发送心跳消息。 - 心跳超时:通过
setHeartbeatTimeout
方法设置心跳超时定时器,如果在指定时间内没有收到心跳响应,则增加超时计数器。 - 重置心跳超时:在
resetHeartbeatTimeout
方法中重置心跳超时计数器,并重新设置超时定时器。
- 发送心跳:通过
-
断线重连:
- 重连逻辑:在
reconnect
方法中实现重连逻辑,使用指数退避策略增加重连间隔时间。 - 最大重连次数:通过
maxReconnectAttempts
控制最大重连次数,避免无限重连。
- 重连逻辑:在
-
心跳超时重连:
- 心跳超时计数器:通过
heartbeatTimeoutCount
记录连续的心跳超时次数。 - 最大心跳超时次数:通过
maxHeartbeatTimeouts
控制最大心跳超时次数,只有在达到指定次数时才进行重连。
- 心跳超时计数器:通过
-
消息发送与缓存:
- 发送消息:通过
send
方法发送消息,如果连接未打开,则将消息缓存到messageQueue
中。 - 消息队列:通过
flushMessageQueue
方法在连接打开后发送缓存的消息。
- 发送消息:通过
-
手动关闭连接:
- 关闭连接:通过
close
方法手动关闭 WebSocket 连接,并清理所有定时器和事件监听器。
- 关闭连接:通过
使用示例
文件中提供了一个使用示例,展示了如何创建 WebSocketClient
实例并设置回调函数来处理连接打开、消息接收、连接关闭和错误事件。
const wsClient = new WebSocketClient("ws://example.com/socket", {
onOpen: () => console.log("连接已打开"),
onMessage: (event) => console.log("收到消息:", event.data),
onClose: (event) => console.log("连接已关闭", event.code, event.reason),
onError: (error) => console.error("连接错误:", error),
});
// 发送消息
wsClient.send({ type: "message", content: "Hello, Server!" });
// 关闭连接
// wsClient.close();
总结
这个文件实现了一个功能全面的 WebSocket
客户端类,能够处理常见的 WebSocket
连接问题,包括心跳机制、断线重连和心跳超时重连等,适用于需要稳定 WebSocket
连接的场景。