目录
长连接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只在组件挂载时运行一次
原理
- 连接失败后会进入stompClient.connect的(err) =>方法,在里面进行重连
- 重连成功后不会重新订阅,
第一种,需要监视是否重新订阅成功,并且有几个页面就要监视几次,因为链接和订阅是不同的,浪费资源
第二种,进行判断是否是重新订阅 如果是则重新刷新页面(我选择的是这种)