# WebSocketClient - WebSocket 客户端封装类
# 简介
WebSocketClient 是一个功能完善的 WebSocket 客户端封装类,提供了自动重连、心跳检测、消息队列、事件监听等实用功能。适用于需要实时双向通信的应用场景。
# 主要特性
- ✅ 自动重连:连接断开后自动尝试重新连接,可配置重连间隔和最大重连次数
- ✅ 心跳检测:定时发送心跳包保持连接活跃,防止连接超时
- ✅ 消息队列:连接未建立时自动缓存消息,连接成功后自动发送
- ✅ 智能错误处理:达到最大重连次数后自动清理队列,防止内存泄漏
- ✅ 事件监听:支持监听连接、断开、消息、错误、重连等事件
- ✅ 连接状态管理:提供完整的连接状态跟踪和查询
- ✅ TypeScript 支持:完整的类型定义和智能提示
- ✅ 调试模式:可选的调试日志输出
# 安装
npm install xxm-test-js
# 基本用法
# 创建实例
import { WebSocketClient } from 'xxm-test-js';
// 创建 WebSocket 客户端实例
const ws = new WebSocketClient('ws://localhost:8080');
// 连接到服务器
ws.connect();
# 带配置选项的创建
const ws = new WebSocketClient('ws://localhost:8080', {
reconnect: true, // 启用自动重连
reconnectInterval: 3000, // 重连间隔 3 秒
maxReconnectAttempts: 10, // 最多重连 10 次
heartbeat: true, // 启用心跳检测
heartbeatInterval: 30000, // 心跳间隔 30 秒
heartbeatMessage: 'ping', // 心跳消息内容
connectionTimeout: 10000, // 连接超时时间 10 秒
debug: true, // 启用调试日志
});
# 配置选项
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
reconnect | boolean | true | 是否启用自动重连 |
reconnectInterval | number | 5000 | 重连间隔时间(毫秒) |
maxReconnectAttempts | number | Infinity | 最大重连次数 |
heartbeat | boolean | true | 是否启用心跳检测 |
heartbeatInterval | number | 30000 | 心跳间隔时间(毫秒) |
heartbeatMessage | string \| object | 'ping' | 心跳消息内容 |
connectionTimeout | number | 10000 | 连接超时时间(毫秒) |
protocols | string \| string[] | undefined | WebSocket 子协议 |
debug | boolean | false | 是否启用调试日志 |
# API 方法
# connect()
建立 WebSocket 连接。
ws.connect();
# disconnect(code?, reason?)
关闭 WebSocket 连接。
参数:
code(可选): 关闭状态码reason(可选): 关闭原因
ws.disconnect();
// 或指定关闭码和原因
ws.disconnect(1000, '正常关闭');
# send(data)
发送消息到服务器。支持字符串、对象、ArrayBuffer、Blob 等类型。
参数:
data: 要发送的数据
行为说明:
- 连接已建立:立即发送消息
- 连接未建立但正在重连:消息加入队列,连接成功后自动发送
- 已达到最大重连次数:拒绝发送,触发
error事件
// 发送字符串
ws.send('Hello Server');
// 发送对象(自动转换为 JSON)
ws.send({ type: 'chat', message: 'Hello', userId: 123 });
// 发送二进制数据
const buffer = new ArrayBuffer(8);
ws.send(buffer);
// 处理发送失败的情况
ws.on('error', (error) => {
if (error.message?.includes('无法发送消息')) {
console.error('连接已失败,无法发送消息');
}
});
# on(event, callback)
监听事件。
参数:
event: 事件类型('open' | 'close' | 'message' | 'error' | 'reconnect')callback: 事件回调函数
ws.on('open', () => {
console.log('连接已建立');
});
ws.on('message', (data) => {
console.log('收到消息:', data);
});
ws.on('error', (error) => {
console.error('发生错误:', error);
});
ws.on('close', (event) => {
console.log('连接已关闭:', event.code, event.reason);
});
ws.on('reconnect', (info) => {
console.log('正在重连,第', info.attempt, '次尝试');
});
# off(event, callback)
移除事件监听。
参数:
event: 事件类型callback: 要移除的回调函数
const messageHandler = (data) => {
console.log('收到消息:', data);
};
ws.on('message', messageHandler);
// 移除监听
ws.off('message', messageHandler);
# getReadyState()
获取当前连接状态码。
返回值:
0: CONNECTING(正在连接)1: OPEN(已连接)2: CLOSING(正在关闭)3: CLOSED(已关闭)
const state = ws.getReadyState();
console.log('连接状态码:', state);
# getStatus()
获取当前连接状态的中文描述。
返回值: string
const status = ws.getStatus();
console.log('连接状态:', status); // 输出: "已连接"
# destroy()
销毁实例,清理所有资源(包括定时器、事件监听器等)。
ws.destroy();
# 使用示例
# 示例 1:聊天应用
import { WebSocketClient } from 'xxm-test-js';
class ChatApp {
private ws: WebSocketClient;
constructor() {
this.ws = new WebSocketClient('ws://chat.example.com/ws', {
reconnect: true,
heartbeatInterval: 30000,
debug: true,
});
this.setupListeners();
this.ws.connect();
}
private setupListeners() {
this.ws.on('open', () => {
console.log('✅ 连接成功');
this.updateStatus('在线');
});
this.ws.on('message', (data) => {
if (data.type === 'chat') {
this.displayMessage(data);
}
});
this.ws.on('error', (error) => {
console.error('❌ 连接错误:', error);
});
this.ws.on('close', () => {
console.log('⚠️ 连接已断开');
this.updateStatus('离线');
});
this.ws.on('reconnect', (info) => {
console.log(`🔄 正在重连... (第 ${info.attempt} 次尝试)`);
});
}
sendMessage(message: string) {
this.ws.send({
type: 'chat',
message: message,
timestamp: Date.now(),
});
}
private displayMessage(data: any) {
console.log(`[${data.username}]: ${data.message}`);
}
private updateStatus(status: string) {
console.log('状态:', status);
}
disconnect() {
this.ws.disconnect();
}
}
// 使用
const chat = new ChatApp();
chat.sendMessage('Hello, World!');
# 示例 2:实时数据监控
import { WebSocketClient } from 'xxm-test-js';
class DataMonitor {
private ws: WebSocketClient;
private dataHandlers: Map<string, Function> = new Map();
constructor(url: string) {
this.ws = new WebSocketClient(url, {
reconnect: true,
reconnectInterval: 5000,
heartbeat: true,
heartbeatMessage: { type: 'ping' },
});
this.ws.on('message', this.handleData.bind(this));
this.ws.connect();
}
// 订阅数据流
subscribe(dataType: string, handler: Function) {
this.dataHandlers.set(dataType, handler);
this.ws.send({
action: 'subscribe',
dataType: dataType,
});
}
// 取消订阅
unsubscribe(dataType: string) {
this.dataHandlers.delete(dataType);
this.ws.send({
action: 'unsubscribe',
dataType: dataType,
});
}
private handleData(data: any) {
const handler = this.dataHandlers.get(data.type);
if (handler) {
handler(data.payload);
}
}
}
// 使用
const monitor = new DataMonitor('ws://monitor.example.com');
monitor.subscribe('temperature', (data) => {
console.log('温度:', data.value, '°C');
});
monitor.subscribe('humidity', (data) => {
console.log('湿度:', data.value, '%');
});
# 示例 3:在 Vue 3 中使用
<template>
<div>
<div>连接状态: {{ status }}</div>
<div>消息列表:</div>
<ul>
<li v-for="msg in messages" :key="msg.id">{{ msg.content }}</li>
</ul>
<input v-model="inputMessage" @keyup.enter="sendMessage" />
<button @click="sendMessage">发送</button>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { WebSocketClient } from 'xxm-test-js';
const ws = ref<WebSocketClient | null>(null);
const status = ref('未连接');
const messages = ref<any[]>([]);
const inputMessage = ref('');
onMounted(() => {
ws.value = new WebSocketClient('ws://localhost:8080', {
debug: true,
});
ws.value.on('open', () => {
status.value = '已连接';
});
ws.value.on('close', () => {
status.value = '已断开';
});
ws.value.on('message', (data) => {
messages.value.push({
id: Date.now(),
content: data,
});
});
ws.value.connect();
});
onUnmounted(() => {
ws.value?.destroy();
});
const sendMessage = () => {
if (inputMessage.value && ws.value) {
ws.value.send(inputMessage.value);
inputMessage.value = '';
}
};
</script>
# 示例 4:在 React 中使用
import React, { useEffect, useState } from 'react';
import { WebSocketClient } from 'xxm-test-js';
function ChatComponent() {
const [ws, setWs] = useState<WebSocketClient | null>(null);
const [status, setStatus] = useState('未连接');
const [messages, setMessages] = useState<string[]>([]);
const [input, setInput] = useState('');
useEffect(() => {
const client = new WebSocketClient('ws://localhost:8080');
client.on('open', () => setStatus('已连接'));
client.on('close', () => setStatus('已断开'));
client.on('message', (data) => {
setMessages((prev) => [...prev, data]);
});
client.connect();
setWs(client);
return () => {
client.destroy();
};
}, []);
const sendMessage = () => {
if (input && ws) {
ws.send(input);
setInput('');
}
};
return (
<div>
<div>状态: {status}</div>
<div>
{messages.map((msg, index) => (
<div key={index}>{msg}</div>
))}
</div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
/>
<button onClick={sendMessage}>发送</button>
</div>
);
}
export default ChatComponent;
# 事件说明
# open 事件
连接成功建立时触发。
ws.on('open', (event) => {
console.log('连接已建立');
});
# close 事件
连接关闭时触发。
ws.on('close', (event: CloseEvent) => {
console.log('连接关闭', event.code, event.reason);
});
# message 事件
收到服务器消息时触发。如果消息是 JSON 格式,会自动解析。
ws.on('message', (data) => {
console.log('收到消息:', data);
});
# error 事件
发生错误时触发。包括连接错误、发送失败、达到最大重连次数等情况。
ws.on('error', (error) => {
console.error('发生错误:', error);
// 判断是否为重连失败
if (error.message?.includes('无法发送消息')) {
console.error('已达到最大重连次数,连接已失败');
// 可以在此通知用户或执行其他操作
}
});
# reconnect 事件
开始重连时触发。
ws.on('reconnect', (info) => {
console.log(`正在第 ${info.attempt} 次重连`);
});
# 最佳实践
# 1. 合理设置心跳间隔
根据服务器的超时设置来配置心跳间隔,一般建议设置为服务器超时时间的 1/2 或 2/3。
const ws = new WebSocketClient('ws://example.com', {
heartbeatInterval: 30000, // 30 秒
heartbeatMessage: { type: 'ping', timestamp: Date.now() },
});
# 2. 处理重连逻辑
在重连时可能需要重新进行身份验证或订阅数据。建议监听重连失败事件。
ws.on('open', () => {
// 发送认证信息
ws.send({
type: 'auth',
token: localStorage.getItem('token'),
});
// 重新订阅数据
ws.send({
type: 'subscribe',
channels: ['channel1', 'channel2'],
});
});
// 监听重连失败
ws.on('error', (error) => {
if (error.message?.includes('无法发送消息')) {
// 已达到最大重连次数
console.error('连接失败,请检查网络或稍后重试');
// 可以显示重连按钮让用户手动重连
showReconnectButton();
}
});
# 3. 使用消息队列
在连接建立之前发送的消息会自动加入队列,连接成功后自动发送。
注意: 如果达到最大重连次数,消息队列会被自动清空以防止内存泄漏,后续发送的消息会被拒绝。
const ws = new WebSocketClient('ws://example.com', {
maxReconnectAttempts: 5, // 设置最大重连次数
});
ws.connect();
// 即使连接还未建立,消息也会被加入队列
ws.send({ type: 'message', content: 'Hello' });
// 监听发送失败
ws.on('error', (error) => {
if (error.message?.includes('无法发送消息')) {
// 重连失败后的消息会触发此错误
console.error('消息发送失败,连接已断开');
}
});
# 4. 及时清理资源
在组件卸载或页面关闭时,记得调用 destroy() 方法清理资源。
// 在组件卸载时
onUnmounted(() => {
ws.destroy();
});
// 或在 beforeunload 事件中
window.addEventListener('beforeunload', () => {
ws.disconnect();
});
# 5. 错误处理
添加完善的错误处理逻辑。
ws.on('error', (error) => {
console.error('WebSocket 错误:', error);
// 发送错误日志到监控系统
sendErrorLog(error);
});
ws.on('close', (event) => {
if (event.code !== 1000) {
// 非正常关闭
console.warn('连接异常关闭:', event.code, event.reason);
}
});
# 注意事项
- 浏览器兼容性:WebSocket API 在所有现代浏览器中都得到支持,但在旧版本浏览器中可能不可用。
- 连接限制:浏览器对同一域名的 WebSocket 连接数量有限制,通常为 6-8 个。
- 跨域问题:WebSocket 连接受同源策略限制,服务器需要正确配置 CORS。
- 安全性:生产环境建议使用
wss://(WebSocket Secure)协议。 - 消息大小:避免发送过大的消息,可能导致性能问题或连接中断。
- 重连失败处理:达到最大重连次数后,消息队列会被自动清空,后续
send()调用会触发error事件。建议监听此事件并提供用户反馈。 - 内存管理:长时间运行的应用应合理设置
maxReconnectAttempts,避免无限重连导致资源浪费。
# 浏览器支持
- Chrome 16+
- Firefox 11+
- Safari 7+
- Edge 12+
- Opera 12.1+
- IE 10+
# 许可证
MIT