useStomp
STOMP 协议 WebSocket 连接管理 Composable,提供完整的 WebSocket 连接、订阅、重连功能。
功能介绍
useStomp 是一个功能完善的 STOMP WebSocket 客户端封装:
- 🔌 连接管理:自动连接、断开、重连
- 📡 订阅管理:订阅、取消订阅、自动恢复
- 💓 心跳检测:保持连接活跃
- 🔄 自动重连:支持指数退避策略
- 🔐 Token 认证:自动携带认证信息
- 👁️ 标签页感知:标签页激活时自动检查连接
基本用法
typescript
import { useStomp } from '@/composables'
const {
isConnected,
connect,
disconnect,
subscribe,
unsubscribe
} = useStomp()
// 建立连接
onMounted(() => {
connect()
})
// 订阅消息
const subscriptionId = subscribe('/topic/messages', (message) => {
console.log('收到消息:', message.body)
})
// 取消订阅
unsubscribe(subscriptionId)
// 断开连接
onUnmounted(() => {
disconnect()
})配置选项
typescript
interface UseStompOptions {
/** WebSocket 地址,默认使用 VITE_APP_WS_ENDPOINT */
brokerURL?: string
/** 认证 Token,默认使用 getAccessToken() */
token?: string
/** 重连延迟(毫秒),默认 15000 */
reconnectDelay?: number
/** 连接超时(毫秒),默认 10000 */
connectionTimeout?: number
/** 是否使用指数退避重连,默认 false */
useExponentialBackoff?: boolean
/** 最大重连次数,默认 3 */
maxReconnectAttempts?: number
/** 最大重连延迟(毫秒),默认 60000 */
maxReconnectDelay?: number
/** 是否开启调试日志,默认 false */
debug?: boolean
/** 是否自动恢复订阅,默认 true */
autoRestoreSubscriptions?: boolean
/** 心跳接收间隔(毫秒),默认 4000 */
heartbeatIncoming?: number
/** 心跳发送间隔(毫秒),默认 4000 */
heartbeatOutgoing?: number
}返回值
状态
| 名称 | 类型 | 说明 |
|---|---|---|
| connectionState | Ref<ConnectionState> | 连接状态 |
| isConnected | ComputedRef<boolean> | 是否已连接 |
| reconnectAttempts | Ref<number> | 当前重连次数 |
连接管理
| 方法 | 类型 | 说明 |
|---|---|---|
| connect | () => void | 建立连接 |
| disconnect | (clearSubscriptions?: boolean) => void | 断开连接 |
| cleanup | () => void | 清理资源 |
订阅管理
| 方法 | 类型 | 说明 |
|---|---|---|
| subscribe | (destination, callback) => string | 订阅主题 |
| unsubscribe | (subscriptionId) => void | 取消订阅 |
| unsubscribeDestination | (destination) => void | 取消指定主题订阅 |
统计信息
| 方法 | 类型 | 说明 |
|---|---|---|
| getActiveSubscriptionCount | () => number | 获取活动订阅数 |
| getRegisteredSubscriptionCount | () => number | 获取注册订阅数 |
连接状态
typescript
enum ConnectionState {
DISCONNECTED = 'DISCONNECTED', // 已断开
CONNECTING = 'CONNECTING', // 连接中
CONNECTED = 'CONNECTED', // 已连接
RECONNECTING = 'RECONNECTING' // 重连中
}完整示例
vue
<template>
<div>
<el-tag :type="isConnected ? 'success' : 'danger'">
{{ isConnected ? '已连接' : '未连接' }}
</el-tag>
<el-button @click="connect" :disabled="isConnected">
连接
</el-button>
<el-button @click="disconnect" :disabled="!isConnected">
断开
</el-button>
<div v-for="msg in messages" :key="msg.id">
{{ msg.content }}
</div>
</div>
</template>
<script setup lang="ts">
import { useStomp } from '@/composables'
interface Message {
id: string
content: string
timestamp: number
}
const messages = ref<Message[]>([])
const {
isConnected,
connect,
disconnect,
subscribe,
cleanup
} = useStomp({
debug: true,
reconnectDelay: 5000,
maxReconnectAttempts: 5,
useExponentialBackoff: true
})
// 连接并订阅
onMounted(() => {
connect()
// 订阅消息主题
subscribe('/topic/chat', (message) => {
const data = JSON.parse(message.body) as Message
messages.value.push(data)
})
// 订阅用户私有消息
subscribe('/user/queue/notifications', (message) => {
ElNotification({
title: '新消息',
message: message.body,
type: 'info'
})
})
})
// 清理资源
onUnmounted(() => {
cleanup()
})
</script>自动重连
默认重连策略
- 最大重连次数:3 次
- 重连延迟:15 秒
- 连接超时:10 秒
指数退避策略
typescript
const { connect } = useStomp({
useExponentialBackoff: true,
reconnectDelay: 1000, // 初始延迟 1 秒
maxReconnectDelay: 60000, // 最大延迟 60 秒
maxReconnectAttempts: 10
})
// 重连延迟:1s -> 2s -> 4s -> 8s -> 16s -> 32s -> 60s -> 60s -> ...订阅自动恢复
断线重连后,之前的订阅会自动恢复:
typescript
const { connect, subscribe } = useStomp({
autoRestoreSubscriptions: true // 默认开启
})
// 订阅会被保存到注册表
subscribe('/topic/messages', handleMessage)
// 断线重连后,订阅会自动恢复标签页可见性处理
当标签页从后台切换到前台时,会自动检查连接状态:
typescript
// 内部实现
document.addEventListener('visibilitychange', () => {
if (!document.hidden && !isConnected && !isManualDisconnect) {
// 自动重连
connect()
}
})环境配置
bash
# .env.development
VITE_APP_WS_ENDPOINT=ws://localhost:8080/ws
# .env.production
VITE_APP_WS_ENDPOINT=wss://api.example.com/ws注意事项
- Token 认证:确保在连接前已登录,Token 会自动携带
- 心跳间隔:标签页失活时浏览器会节流定时器,建议设置较长间隔
- 资源清理:组件卸载时调用
cleanup()或disconnect() - 订阅时机:可以在连接前订阅,连接成功后会自动执行
