首页 > 其他分享 >对 websocket 进行封装 (心跳检测 断开重连 发送事件等等 支持断开重连后发送上次发送的最后一个事件)

对 websocket 进行封装 (心跳检测 断开重连 发送事件等等 支持断开重连后发送上次发送的最后一个事件)

时间:2024-06-19 15:46:48浏览次数:14  
标签:const socket 重连后 eventListeners 发送 callback message event 断开

代码封装: 

 

// websocketService.js
import { ref } from "vue";

const { DEV, VITE_APP_PUSH_WS } = import.meta.env;
const { push_ws } = window.WEB_CONFIG;
const baseWsUrl = DEV ? VITE_APP_PUSH_WS : push_ws;

class WebSocketService {
  constructor(url) {
    this.url = url;
    this.socket = null;
    this.reconnectTimer = null;
    this.heartbeatTimer = null;
    this.socketStatus = false;
    this.reconnectInterval = 5000; // 重连间隔时间
    this.heartbeatInterval = 30000; // 心跳间隔时间
    this.websocketObj = ref(null);
    this.onOpenCallback = null; // 新增用于保存连接成功后的回调函数
    this.eventListeners = {}; // 用于存储事件监听器
    this.lastSentMessage = null; // 存储最后发送的消息
  }

  initSocket(onOpenCallback) {
    this.socket = new WebSocket(this.url);

    this.socket.onopen = () => {
      clearInterval(this.reconnectTimer);
      this.socketStatus = true;
      this.startHeartbeat();
      this.websocketObj.value = this.socket;
      if (onOpenCallback) {
        onOpenCallback();
      }
      if (this.lastSentMessage) {
        this.sendMessage(this.lastSentMessage); // 重连后发送最后一条消息
      }
    };

    this.socket.onmessage = (event) => {
      const data = JSON.parse(event.data);
      const token = window.localStorage.getItem('token') || '';
      if (!token) {
        this.closeSocket();
      }
      if (this.eventListeners[data.event]) {
        this.eventListeners[data.event].forEach(callback => callback(data));
      }
    };

    this.socket.onclose = () => {
      this.handleSocketClose();
    };

    this.socket.onerror = () => {
      this.handleSocketError();
    };
  }

  startHeartbeat() {
    this.heartbeatTimer = setInterval(() => {
      this.socket.send(JSON.stringify({ event: "heartbeat" }));
    }, this.heartbeatInterval);
  }

  stopHeartbeat() {
    clearInterval(this.heartbeatTimer);
  }

  closeSocket() {
    this.stopHeartbeat();
    this.socket.close();
  }

  handleSocketClose() {
    console.log("WebSocket closed");
    this.socketStatus = false;
    this.stopHeartbeat();
    this.reconnect();
  }

  handleSocketError() {
    console.log("WebSocket error");
    this.socketStatus = false;
    this.stopHeartbeat();
    this.reconnect();
  }

  reconnect() {
    if (this.reconnectTimer) return;

    this.reconnectTimer = setInterval(() => {
      this.initSocket(this.onOpenCallback);
    }, this.reconnectInterval);
  }

  sendMessage(message) {
    this.lastSentMessage = message; // 存储最后发送的消息
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(message);
    } else {
      console.error('WebSocket is not open. Ready state is: ' + (this.socket ? this.socket.readyState : 'N/A'));
    }
  }

  addEventListener(event, callback) {
    if (!this.eventListeners[event]) {
      this.eventListeners[event] = [];
    }
    this.eventListeners[event].push(callback);
  }

  removeEventListener(event, callback) {
    if (this.eventListeners[event]) {
      this.eventListeners[event] = this.eventListeners[event].filter(cb => cb !== callback);
    }
  }
}

const wsUrl = `${baseWsUrl}/ws/footballMsg`;
const websocketService = new WebSocketService(wsUrl);
export const newwebsocketObj = websocketService.websocketObj;

export const initWebsocketObj = (onOpenCallback) => {
  websocketService.initSocket(onOpenCallback);
};

export const sendMessage = (message) => {
  websocketService.sendMessage(message);
};

export const closeWebsocket = () => {
  websocketService.closeSocket();
};

export const addEventListener = (event, callback) => {
  websocketService.addEventListener(event, callback);
};

export const removeEventListener = (event, callback) => {
  websocketService.removeEventListener(event, callback);
};

代码使用:

<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { initWebsocketObj, sendMessage, addEventListener, removeEventListener, websocketObj } from './websocketService.js';

const tableData = ref([]);
const standardMatchId = ref('match_id_example'); // 这是一个示例的 match_id,你可以从路由或其他地方获取

// 处理 WebSocket 消息的回调函数
const handleFootballMessageEvent = (data) => {
  if (data.event === 'FootballMessageEvent') {
    const { id = '' } = data.payload || {};
    if (!tableData.value.length || !id.startsWith(standardMatchId.value)) return;
    tableData.value.unshift(data.payload);
    tableData.value = [...new Set(tableData.value.map(JSON.stringify))].map(
      JSON.parse
    );
  }
};

onMounted(() => {
  // 初始化 WebSocket
  initWebsocketObj(() => {
    // 连接成功后发送初始消息
    const message = JSON.stringify({
      event: "subMatch",
      payload: { FootballMessageEvent: [standardMatchId.value] }
    });
    sendMessage(message);
  });

  // 添加事件监听器
  addEventListener('FootballMessageEvent', handleFootballMessageEvent);

  // 监听 tableData 的变化
  watch(tableData, (newValue) => {
    const standardMatchIds = newValue.map(item => item.standard_match_id + '');
    const params = {
      BetMarketEvent: standardMatchIds,
      FootballEvent: standardMatchIds
    };
    const message = JSON.stringify({ event: "subMatch", payload: params });
    sendMessage(message);
  });

  // 组件卸载时移除事件监听器
  onUnmounted(() => {
    removeEventListener('FootballMessageEvent', handleFootballMessageEvent);
    websocketObj.value && websocketObj.value.close();
  });
});
</script>

<template>
  <div>
    <table>
      <thead>
        <tr>
          <th>Match ID</th>
          <th>Event</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in tableData" :key="item.standard_match_id">
          <td>{{ item.standard_match_id }}</td>
          <td>{{ item.event }}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

  

标签:const,socket,重连后,eventListeners,发送,callback,message,event,断开
From: https://www.cnblogs.com/guangzhou11/p/18256372

相关文章

  • 使用 curl 发送请求
    简介cURL是一个通过URL传输数据的,功能强大的命令行工具。cURL可以与ChromeDevtool工具配合使用,把浏览器发送的真实请求还原出来,附带认证信息,脱离浏览器执行,方便开发者重放请求、修改参数调试,编写脚本。也可以单独使用,根据自己的需求构造请求调整参数,构造多种接口测试场景......
  • 项目运维时,某用户通过RDP远程桌面连接服务器...任务管理器显示用户状态断开连接!记录运
    目录问题出现解决方式测试参考  今天处理项目运维问题,发现服务器任务管理器出现用户状态断开连接......问题出现项目运维时,某用户通过rdp远程桌面连接Windowsserver服务器时,出现服务器发布的进度计划无法执行,打开服务器任务管理界面出现用户状态断开连接标志,如下......
  • 问题:如果发送者先运行,而队列是在接收者中定义的,// declare a server-named queue var
    在RabbitMQ中,当你使用交换机(Exchange)和绑定(Binding)时,消息的路由是由交换机类型和绑定键(RoutingKey)来决定的,而不是直接由队列名称来决定的。交换机负责接收生产者发送的消息并根据一定的规则将这些消息路由到一个或多个队列中。问题解释与RabbitMQ的原理发送消息时的行为:发送......
  • STM学习记录(六)————串口的发送接收
    文章目录前言一、串口结构体及库函数二、实现串口发送(库函数)1.程序设计2.代码三.串口接收1.串口接收(普通)2.串口中断接收3.串口发送字符串函数4.串口实现printf(重定向)5.串口实现scanf(重定向)前言一个学习单片机的小白~有错误评论区或私信指出~一、串口结构体及......
  • curl命令行发送post/get请求
    文章目录curl概述post请求get请求curl概述curl是一个命令行实用程序,允许用户创建网络请求curl在Windows、Linux和Mac上皆可使用post请求一个简单的POST请求-X:指定与远程服务器通信时将使用哪种HTTP请求方法curl-XPOSThttp://example.comPOST......
  • gitlab自动定时备份文件,备份失败发送邮件
    一、需求为预防gitlab出现故障,每天定时备份,备份完成后把之前的备份文件删除,备份成功或失败的时候自动发送邮件提醒,这里的gitlab为docker部署。二、备份命令准备1)备份命令 创建一个gitlab_auto_backup.sh文件,文件内容#!/bin/bash#进入GitLab容器并执行备份--gitlab为do......
  • Http压缩zip,加密base64发送与获取
    //数据压缩成Zip再发送publicstaticstringZipBasebyte(stringxml){byte[]bytesToCompress=Encoding.GetEncoding("GBK").GetBytes(xml);MemoryStreamms=newMemoryStream();ZipEntryze=newZipEntry("servlets......
  • 抖音验证签名和接口含中文签名,需要在发送端加上utf8编码
    抖音验证签名和接口含中文签名,需要在发送端加上utf8编码抖音验签和抖音异步通知回调验签解决:是对整个接收的字符串做验签,而不是部分数据做验签解决中文参数问题,否则中文乱码报验签错误 签名算法https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/serve......
  • JavaScript发送电子邮件
    JavaScript发送电子邮件constnodemailer=require("nodemailer");consttransporter=nodemailer.createTransport({host:"smtp.qq.com",//SMTP服务器地址port:465,//SMTP端口,对于SSL使用465secure:true,//对端口465使用“true”,对所有其他端口使用“f......
  • 利用某些平台(聚合API、百度AI、科大讯飞API)的API接口,利用HTTP协议向服务器发送请求,并
    要使用C语言通过HTTP协议向服务器发送请求并接收响应,你可以使用如libcurl这样的库来发送HTTP请求。libcurl是一个免费且易于使用的客户端URL传输库,支持多种协议,包括HTTP。同时,为了解析服务器响应中的JSON数据,你可以使用cJSON库,这是一个轻量级的JSON解析库。以下是一个简单的示例......