Skip to content

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
}

返回值

状态

名称类型说明
connectionStateRef<ConnectionState>连接状态
isConnectedComputedRef<boolean>是否已连接
reconnectAttemptsRef<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

注意事项

  1. Token 认证:确保在连接前已登录,Token 会自动携带
  2. 心跳间隔:标签页失活时浏览器会节流定时器,建议设置较长间隔
  3. 资源清理:组件卸载时调用 cleanup()disconnect()
  4. 订阅时机:可以在连接前订阅,连接成功后会自动执行

相关链接

基于 MIT 许可发布