|
|
@@ -10,11 +10,16 @@ class StompClient {
|
|
|
this.subscriptions = new Map(); // pageCode -> subscription
|
|
|
this.connectedCallbackQueue = [];
|
|
|
this.connected = false;
|
|
|
+ this.reconnectTimer = null; // 重连计时器
|
|
|
+ this.reconnectInterval = 5000; // 重连间隔时间(ms)
|
|
|
+ this.maxReconnectAttempts = 0; // 最大重连次数,0表示无限重试
|
|
|
+ this.reconnectAttempts = 0; // 当前重连尝试次数
|
|
|
}
|
|
|
|
|
|
// 初始化连接
|
|
|
connect() {
|
|
|
- if (this.client) return;
|
|
|
+ // 如果已有连接或正在重连中,则不再重复连接
|
|
|
+ if (this.client || this.reconnectTimer) return;
|
|
|
|
|
|
const socket = new SockJS(this.url);
|
|
|
this.client = new Client({
|
|
|
@@ -23,7 +28,14 @@ class StompClient {
|
|
|
// debug: (str) => console.log('[STOMP]', str),
|
|
|
onConnect: () => {
|
|
|
this.connected = true;
|
|
|
+ this.reconnectAttempts = 0; // 重置重连计数器
|
|
|
+ clearTimeout(this.reconnectTimer);
|
|
|
+ this.reconnectTimer = null;
|
|
|
+
|
|
|
console.log('STOMP 连接成功');
|
|
|
+ // 重新订阅之前的主题
|
|
|
+ this.restoreSubscriptions();
|
|
|
+ // 执行连接成功后的回调队列
|
|
|
this.connectedCallbackQueue.forEach((cb) => cb());
|
|
|
this.connectedCallbackQueue = [];
|
|
|
},
|
|
|
@@ -31,22 +43,69 @@ class StompClient {
|
|
|
console.error('STOMP 错误', frame.headers['message'], frame.body);
|
|
|
},
|
|
|
onDisconnect: () => {
|
|
|
- this.connected = false;
|
|
|
- console.warn('STOMP 连接断开');
|
|
|
+ this.handleDisconnect();
|
|
|
+ },
|
|
|
+ onWebSocketClose: () => {
|
|
|
+ this.handleDisconnect();
|
|
|
},
|
|
|
+ onWebSocketError: (error) => {
|
|
|
+ console.error('WebSocket 错误:', error);
|
|
|
+ this.handleDisconnect();
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
this.client.activate();
|
|
|
}
|
|
|
|
|
|
+ // 处理断开连接
|
|
|
+ handleDisconnect() {
|
|
|
+ if (!this.connected) return; // 已经处于断开状态,无需处理
|
|
|
+
|
|
|
+ this.connected = false;
|
|
|
+ this.client = null;
|
|
|
+ console.warn('STOMP 连接断开,准备重连...');
|
|
|
+
|
|
|
+ // 如果达到最大重连次数限制,则停止重连
|
|
|
+ if (this.maxReconnectAttempts > 0 && this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
|
+ console.error(`已达到最大重连次数(${this.maxReconnectAttempts}),停止重连`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 启动重连计时器
|
|
|
+ this.reconnectTimer = setTimeout(() => {
|
|
|
+ this.reconnectAttempts++;
|
|
|
+ console.log(`正在进行第 ${this.reconnectAttempts} 次重连...`);
|
|
|
+ this.connect();
|
|
|
+ }, this.reconnectInterval);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 恢复之前的订阅
|
|
|
+ restoreSubscriptions() {
|
|
|
+ if (this.subscriptions.size === 0 || !this.client) return;
|
|
|
+
|
|
|
+ console.log(`重新订阅 ${this.subscriptions.size} 个主题`);
|
|
|
+ // 保存当前的订阅信息
|
|
|
+ const subscriptions = Array.from(this.subscriptions.entries());
|
|
|
+ // 清空现有订阅映射
|
|
|
+ this.subscriptions.clear();
|
|
|
+
|
|
|
+ // 重新订阅所有主题
|
|
|
+ subscriptions.forEach(([pageCode, { onMessage }]) => {
|
|
|
+ this.subscribeToPage(pageCode, onMessage, true);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
// 订阅页面数据
|
|
|
- subscribeToPage(pageCode, onMessage) {
|
|
|
+ // restoreFlag用于标识是否是重连后的恢复订阅
|
|
|
+ subscribeToPage(pageCode, onMessage, restoreFlag = false) {
|
|
|
if (!pageCode || typeof onMessage !== 'function') return;
|
|
|
|
|
|
const doSubscribe = () => {
|
|
|
const topic = `/topic/page/${pageCode}`;
|
|
|
if (this.subscriptions.has(pageCode)) {
|
|
|
- console.warn(`已订阅过页面 ${pageCode}`);
|
|
|
+ if (!restoreFlag) {
|
|
|
+ console.warn(`已订阅过页面 ${pageCode}`);
|
|
|
+ }
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -56,8 +115,15 @@ class StompClient {
|
|
|
onMessage(data);
|
|
|
});
|
|
|
|
|
|
- this.subscriptions.set(pageCode, subscription);
|
|
|
- console.log(`订阅页面 ${pageCode} 成功`);
|
|
|
+ // 存储订阅对象和回调函数,用于重连后恢复
|
|
|
+ this.subscriptions.set(pageCode, {
|
|
|
+ subscription,
|
|
|
+ onMessage
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!restoreFlag) {
|
|
|
+ console.log(`订阅页面 ${pageCode} 成功`);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
if (this.connected) {
|
|
|
@@ -70,22 +136,40 @@ class StompClient {
|
|
|
|
|
|
// 取消订阅
|
|
|
unsubscribeFromPage(pageCode) {
|
|
|
- const subscription = this.subscriptions.get(pageCode);
|
|
|
- if (subscription) {
|
|
|
- subscription.unsubscribe();
|
|
|
+ const subscriptionObj = this.subscriptions.get(pageCode);
|
|
|
+ if (subscriptionObj && subscriptionObj.subscription) {
|
|
|
+ subscriptionObj.subscription.unsubscribe();
|
|
|
this.subscriptions.delete(pageCode);
|
|
|
console.log(`已取消订阅页面 ${pageCode}`);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 主动断开连接
|
|
|
+ // 主动断开连接,不触发自动重连
|
|
|
disconnect() {
|
|
|
+ // 清除重连计时器
|
|
|
+ if (this.reconnectTimer) {
|
|
|
+ clearTimeout(this.reconnectTimer);
|
|
|
+ this.reconnectTimer = null;
|
|
|
+ }
|
|
|
+
|
|
|
if (this.client) {
|
|
|
this.client.deactivate();
|
|
|
this.client = null;
|
|
|
- this.connected = false;
|
|
|
- this.subscriptions.clear();
|
|
|
- console.log('STOMP 客户端已断开');
|
|
|
+ }
|
|
|
+
|
|
|
+ this.connected = false;
|
|
|
+ this.subscriptions.clear();
|
|
|
+ this.reconnectAttempts = 0;
|
|
|
+ console.log('STOMP 客户端已手动断开');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置重连参数
|
|
|
+ setReconnectOptions(interval, maxAttempts) {
|
|
|
+ if (interval && typeof interval === 'number' && interval > 0) {
|
|
|
+ this.reconnectInterval = interval;
|
|
|
+ }
|
|
|
+ if (maxAttempts !== undefined && typeof maxAttempts === 'number' && maxAttempts >= 0) {
|
|
|
+ this.maxReconnectAttempts = maxAttempts;
|
|
|
}
|
|
|
}
|
|
|
}
|