uni-app的WebSocket
uni-app的WebSocket封装类,支持心跳检测、心跳超时重连、断线重连等。uni.connectSocket
TypeScript封装类
ts
/**
* WebSocket 封装类
* - 支持心跳检测
* - 支持心跳超时延时重连
* - 支持断线延时重连
*/
export class SuWebSocket {
// WebSocket 地址
private readonly url: string
// WebSocket 任务
private socketTask: any = null
// 心跳检测定时器
private heartBeatTimer: any = null
// 重连定时器
private reconnectTimer: any = null
// 心跳超时检测定时器
private heartBeatTimeoutTimer: any = null
// 重连间隔(毫秒)
private reconnectDelay: number = 5000
// 心跳检测间隔(毫秒)
private heartBeatInterval: number = 30000
// 心跳检测超时(毫秒)
private heartBeatTimeout: number = 10000
// 是否处于连接状态
private isConnected: boolean = false
// 是否处于连接中
private isConnecting: boolean = false
// 重连次数
private reconnectAttempts: number = 0
// 是否允许重连
private allowReconnect: boolean = true
// 回调函数:连接成功
private onOpenCallback: (() => void) | null = null
// 回调函数:接收到消息
private onMessageCallback: ((data: any) => void) | null = null
// 回调函数:连接关闭
private onCloseCallback: (() => void) | null = null
// 回调函数:连接错误
private onErrorCallback: ((error: any) => void) | null = null
/**
* 构造函数
* @param url WebSocket 地址
*/
constructor(url: string) {
this.url = url
}
/**
* 设置连接成功回调
*/
onOpen(callback: () => void): void {
this.onOpenCallback = callback
}
/**
* 设置消息接收回调
*/
onMessage(callback: (data: any) => void): void {
this.onMessageCallback = callback
}
/**
* 设置连接关闭回调
*/
onClose(callback: () => void): void {
this.onCloseCallback = callback
}
/**
* 设置错误回调
*/
onError(callback: (error: any) => void): void {
this.onErrorCallback = callback
}
/**
* 设置是否允许重连
* @param allow 是否允许重连
*/
setAllowReconnect(allow: boolean): void {
this.allowReconnect = allow;
}
/**
* 建立 WebSocket 连接
*/
connect(): void {
if (this.isConnecting || this.isConnected) {
return
}
this.allowReconnect = true;
this.isConnecting = true
this.socketTask = uni.connectSocket({
url: this.url,
success: () => {
console.log('WebSocket 连接成功')
},
fail: (err) => {
console.error('WebSocket 连接失败', err)
this.handleReconnect()
}
})
this.bindSocketEvents()
}
/**
* 绑定 WebSocket 事件
*/
private bindSocketEvents(): void {
// 监听连接打开
this.socketTask.onOpen(() => {
console.log('WebSocket 连接已打开')
this.isConnecting = false
this.isConnected = true
this.reconnectAttempts = 0
this.startHeartBeat()
if (this.onOpenCallback) {
this.onOpenCallback()
}
})
// 监听消息接收
this.socketTask.onMessage((res: any) => {
console.log('收到服务器消息:', res.data)
if (res.data === 'pong') {
this.handlePong()
return
}
if (this.onMessageCallback) {
this.onMessageCallback(res.data)
}
})
// 监听连接关闭
this.socketTask.onClose(() => {
console.log('WebSocket 连接已关闭')
this.isConnected = false
this.isConnecting = false
this.stopHeartBeat()
if (this.onCloseCallback) {
this.onCloseCallback()
}
this.handleReconnect()
})
// 监听连接错误
this.socketTask.onError((err: any) => {
console.error('WebSocket 发生错误:', err)
this.isConnected = false
this.isConnecting = false
this.stopHeartBeat()
if (this.onErrorCallback) {
this.onErrorCallback(err)
}
this.handleReconnect()
})
}
/**
* 处理 pong 响应
*/
private handlePong(): void {
// 清除心跳超时定时器
if (this.heartBeatTimeoutTimer) {
clearTimeout(this.heartBeatTimeoutTimer)
this.heartBeatTimeoutTimer = null
}
console.log('收到服务器 pong 响应')
}
/**
* 处理心跳超时
*/
private handleHeartBeatTimeout(): void {
console.warn('心跳超时,未收到服务器 pong 响应')
// 关闭当前连接并触发重连
this.close()
this.handleReconnect()
}
/**
* 处理重连逻辑
*/
private handleReconnect(): void {
// 如果不允许重连,则不执行重连逻辑
if (!this.allowReconnect) {
return;
}
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer)
}
this.reconnectTimer = setTimeout(() => {
this.reconnectAttempts++
console.log(`WebSocket 尝试重连第 ${this.reconnectAttempts} 次`)
this.connect()
}, this.reconnectDelay)
}
/**
* 发送消息
*/
send(data: any): void {
if (this.socketTask && this.isConnected) {
this.socketTask.send({
data: data,
success: () => {
console.log('消息发送成功')
},
fail: (err: any) => {
console.error('消息发送失败', err)
}
})
} else {
console.warn('WebSocket 未连接,无法发送消息')
}
}
/**
* 开始心跳检测
*/
private startHeartBeat(): void {
this.stopHeartBeat()
this.heartBeatTimer = setInterval(() => {
this.sendPing()
}, this.heartBeatInterval)
}
/**
* 发送 ping 心跳包
*/
private sendPing(): void {
// 发送 ping
this.send('ping')
// 启动心跳超时检测
if (this.heartBeatTimeoutTimer) {
clearTimeout(this.heartBeatTimeoutTimer)
}
this.heartBeatTimeoutTimer = setTimeout(() => {
this.handleHeartBeatTimeout()
}, this.heartBeatTimeout)
}
/**
* 停止心跳检测
*/
private stopHeartBeat(): void {
if (this.heartBeatTimer) {
clearInterval(this.heartBeatTimer)
this.heartBeatTimer = null
}
// 清除心跳超时定时器
if (this.heartBeatTimeoutTimer) {
clearTimeout(this.heartBeatTimeoutTimer)
this.heartBeatTimeoutTimer = null
}
}
/**
* 销毁WebSocket实例
*/
destroy(): void {
// 设置不允许重连,防止在关闭过程中触发重连
this.allowReconnect = false;
this.close()
}
/**
* 关闭 WebSocket 连接
*/
close(): void {
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer)
this.reconnectTimer = null
}
this.stopHeartBeat()
if (this.socketTask) {
this.socketTask.close({
code: 1000,
reason: '用户主动关闭连接'
})
this.socketTask = null
}
this.isConnected = false
this.isConnecting = false
}
/**
* 获取连接状态
*/
getConnectedStatus(): { isConnected: boolean; isConnecting: boolean } {
return {
isConnected: this.isConnected,
isConnecting: this.isConnecting
}
}
}
/**
* 创建 WebSocket 实例
* @param url
* @return SuWebSocket
*/
export function makeWebSocket(url: string): SuWebSocket {
return new SuWebSocket(url)
}使用
vue
<script setup lang="ts">import { onMounted, onUnmounted } from 'vue'
// 创建 WebSocket 实例
const wsManager = new SuWebSocket('wss://example.com/websocket')
// 处理接收到的消息
function handleMessage(data: string) {
if (data === 'pong') {
return
}
try {
const message = JSON.parse(data)
// 根据消息类型处理业务逻辑
switch (message.event) {
case 'refresh_data':
// 更新页面数据
updatePageData(message.data)
break
case 'notification':
// 显示通知
showNotification(message.data)
break
}
} catch (error) {
console.error('解析消息失败:', error)
}
}
// 更新页面数据
function updatePageData(data: any) {
// 实现你的数据更新逻辑
console.log('更新数据:', data)
}
// 显示通知
function showNotification(data: any) {
// 实现你的通知显示逻辑
console.log('显示通知:', data)
}
onMounted(() => {
// 设置回调
wsManager.onOpen(() => {
console.log('WebSocket 连接已建立')
})
wsManager.onMessage(handleMessage)
wsManager.onClose(() => {
console.log('WebSocket 连接已关闭')
})
wsManager.onError((error) => {
console.error('WebSocket 错误:', error)
})
// 建立连接
wsManager.connect()
})
onUnmounted(() => {
// 组件卸载时关闭连接
wsManager.destroy()
})
</script>ts
// 发送文本消息
wsManager.send('hello server')
// 发送 JSON 对象
wsManager.send({
event: 'user_action',
data: {
action: 'click',
element: 'button'
}
})