自学内容网 自学内容网

长连接配置以及断线重连

目录

长连接index 主要进行连接

import SockJS from "sockjs-client";
import Stomp from "stompjs";
import { notification } from "antd";
// 网络请求API
import { nowApiAddressObj } from "../api/nowApiAddressObj";

// 工具
import YaoTokenUtil from "../utils/tokenTool";

notification.config({
  maxCount: 1,
  top: 50,
});
let webSocketJSTiem = null;
// 正在进行重新连接
let isReconnection = false;
function webSocketJS() {
  let socket = null;
  let stompClient = null;
  console.log("yaojunhao 测试测试我是计时器尝试重新连接2");

  return new Promise((resolve, reject) => {
    socket = new SockJS(`${nowApiAddressObj}/scream/api/ws`, null, {
      transports: ["websocket", "xhr-streaming", "xhr-polling"],
      withCredentials: true,
      log: false,
    });
    stompClient = Stomp.over(socket);

    let headers = {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Credentials": true,
      "Access-Control-Allow-Headers": "X-PINGOTHER, Content-Type",
      "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
      "X-Auth-Token": YaoTokenUtil.getToken() || "",
    };

    stompClient.onerror = (err) => {
      console.log("yaojunhao webSocketJS_onerror", err);
      reject(err);
    };

    function tokenError(code) {
      if (code === 1404) {
        // 清除token
        YaoTokenUtil.clearToken();
        // 跳转登录页面
        window.location.href = "/login";
        sessionStorage.setItem("userInfoLoseEfficacy", JSON.stringify(true));
      }
    }

    stompClient.connect(
      headers,
      (frame) => {
        clearTimeout(webSocketJSTiem);
        webSocketJSTiem = null;
        notification.success({
          message: "Api连接成功",
          showProgress: true,
          duration: 2,
        });

        console.log("yaojunhao webSocketJS_connect_连接成功");
        if (isReconnection) {
          location.reload();
        }
        // console.log(frame);
        resolve(stompClient);
      },
      (err) => {
        if (err?.headers?.message == "1404") {
          tokenError(parseInt(err.headers.message));
        } else {
          //连接失败进行重连
          stompClient.disconnect(
            () => {
              notification.error({
                message: "连接失败,正在尝试重新连接",
                showProgress: true,
                duration: 1,
              });
              console.log("STOMP连接已关闭");
              webSocketJSTiem = setTimeout(webSocketJS, 5000);
              isReconnection = true;
            },
            (error) => {
              console.error("关闭STOMP连接时发生错误:", error);
            }
          );
        }
        console.log("yaojunhao webSocketJS_connect_连接失败", err);
        reject(err);
      }
    );
  });
}

// 销毁定时器
function destroyTime() {
  clearTimeout(webSocketJSTiem);
  webSocketJSTiem = null;
}

export { webSocketJS, destroyTime };

其中一项 子项 链接成功后进行订阅


import { webSocketJS, destroyTime } from "../index";
import YaoBasicsUtil from "../../utils/basicsTool";

let stompClient = null;
// 用于保存订阅ID
let subscription = null;

class basketballSingle {
  // 创建webSocketJS
  async createStompClient() {
    stompClient = await webSocketJS();
    console.log("yaojunhao createStompClient_stompClient", stompClient);
  }
  // 订阅消息,并保存订阅ID
  async subscribe(fun) {
    subscription = stompClient.subscribe(
      `/topic/bkSingle/${
        JSON.parse(localStorage.getItem("userTokenInfo"))?.sub
      }`,
      (msg) => {
        console.log("广播成功");
        console.log("yaojunhao 测试测试订阅消息", msg);
        const messagesData = YaoBasicsUtil.jsonStringToJsonObj(msg.body);
        // 给每个参数都添加索引key作为主键
        messagesData.map((item, index) => {
          item.idIndex = index;
        });
        console.log("yaojunhao 测试测试订阅消息转换", messagesData);
        fun(messagesData);
      }
    );
    return subscription;
  }

  // 长链接取消订阅的函数
  unsubscribeFromTopic() {
    destroyTime();
    if (subscription) {
      stompClient.unsubscribe(subscription.id);
      console.log("yaojunhao webSocketJS_已取消订阅");
      // 清理subscription变量,避免内存泄漏
      subscription = null;
    }
  }
}

const basketballSingleSocket = new basketballSingle();
export default basketballSingleSocket;

注意 在页面里必须先连接 再订阅

  // 页面加载完毕时
  useEffect(() => {
    messageApi.open({
      key: messageSinkStateKey,
      type: "loading",
      content: "当前是历史数据,正在获取最新数据",
      duration: 0,
    });
    setSimulationData([...basketballSingleData]);
    console.log(
      "yaojunhao 页面加载完毕时 basketballSingleData",
      basketballSingleData
    );

    // 订阅长连接
    async function getSubscriptionId() {
      await basketballSingle.subscribe((e) => {
        // 判断是不是首次进入
        if (!messageSinkState) {
          messageApi.destroy(messageSinkStateKey);
          messageApi.open({
            key: messageSinkStateKey,
            type: "success",
            content: "成功获取到新数据",
            duration: 2,
          });
          messageSinkState = true;
        }
        console.log("yaojunhao basketballSingle_订阅消息转换", e);

        // 保存到仓库
        dispatch(setBasketballSingleData([...e]));
        setSimulationData([...e]);

        // 设置弹出层中展示数据
        setPopupData({ ...e[popupDataIndex] });
        dispatch(setBasketballSingleModalData({ ...e[popupDataIndex] }));
        console.log("yaojunhao 保存数据 重新渲染页面", [...e]);
      }).id;
    }
    async function createStompClient() {
      await basketballSingle.createStompClient();
      getSubscriptionId();
    }
    createStompClient();
    return () => {
      console.log("yaojunhao 组件销毁时取消订阅");
      basketballSingle.unsubscribeFromTopic();
    };
  }, []); // 空依赖数组表示这个effect只在组件挂载时运行一次

原理

  1. 连接失败后会进入stompClient.connect的(err) =>方法,在里面进行重连
  2. 重连成功后不会重新订阅,
    第一种,需要监视是否重新订阅成功,并且有几个页面就要监视几次,因为链接和订阅是不同的,浪费资源
    第二种,进行判断是否是重新订阅 如果是则重新刷新页面(我选择的是这种)

原文地址:https://blog.csdn.net/YJH15888673903/article/details/143734348

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!