fix: 🐛 修复WebSocket授权令牌验证失败导致连接断线问题
This commit is contained in:
@@ -28,10 +28,10 @@ export interface UseStompOptions {
|
|||||||
export function useStomp(options: UseStompOptions = {}) {
|
export function useStomp(options: UseStompOptions = {}) {
|
||||||
// 默认值:brokerURL 从环境变量中获取,token 从 getAccessToken() 获取
|
// 默认值:brokerURL 从环境变量中获取,token 从 getAccessToken() 获取
|
||||||
const defaultBrokerURL = import.meta.env.VITE_APP_WS_ENDPOINT || "";
|
const defaultBrokerURL = import.meta.env.VITE_APP_WS_ENDPOINT || "";
|
||||||
const defaultToken = getAccessToken();
|
// 不再使用defaultToken,每次连接时直接获取最新token
|
||||||
|
|
||||||
const brokerURL = ref(options.brokerURL ?? defaultBrokerURL);
|
const brokerURL = ref(options.brokerURL ?? defaultBrokerURL);
|
||||||
const token = options.token ?? defaultToken;
|
// 不再存储token,改为在初始化时获取
|
||||||
const reconnectDelay = options.reconnectDelay ?? 8000;
|
const reconnectDelay = options.reconnectDelay ?? 8000;
|
||||||
const connectionTimeout = options.connectionTimeout ?? 10000;
|
const connectionTimeout = options.connectionTimeout ?? 10000;
|
||||||
const useExponentialBackoff = options.useExponentialBackoff ?? false;
|
const useExponentialBackoff = options.useExponentialBackoff ?? false;
|
||||||
@@ -60,11 +60,20 @@ export function useStomp(options: UseStompOptions = {}) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 每次连接前重新获取最新令牌,不依赖之前的token值
|
||||||
|
const currentToken = getAccessToken();
|
||||||
|
|
||||||
|
// 检查令牌是否为空,如果为空则不进行连接
|
||||||
|
if (!currentToken) {
|
||||||
|
console.error("WebSocket连接失败:授权令牌为空,请先登录");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 创建 STOMP 客户端
|
// 创建 STOMP 客户端
|
||||||
client.value = new Client({
|
client.value = new Client({
|
||||||
brokerURL: brokerURL.value,
|
brokerURL: brokerURL.value,
|
||||||
connectHeaders: {
|
connectHeaders: {
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${currentToken}`,
|
||||||
},
|
},
|
||||||
debug: options.debug ? console.log : () => {},
|
debug: options.debug ? console.log : () => {},
|
||||||
reconnectDelay: useExponentialBackoff ? 0 : reconnectDelay, // 使用自定义退避策略时禁用内置重连
|
reconnectDelay: useExponentialBackoff ? 0 : reconnectDelay, // 使用自定义退避策略时禁用内置重连
|
||||||
@@ -95,11 +104,40 @@ export function useStomp(options: UseStompOptions = {}) {
|
|||||||
client.value.onWebSocketClose = (event) => {
|
client.value.onWebSocketClose = (event) => {
|
||||||
isConnected.value = false;
|
isConnected.value = false;
|
||||||
console.log(`WebSocket已关闭: ${event?.code} ${event?.reason}`);
|
console.log(`WebSocket已关闭: ${event?.code} ${event?.reason}`);
|
||||||
|
|
||||||
|
// 如果是授权问题导致的关闭,尝试重新获取令牌
|
||||||
|
if (event?.code === 1000 || event?.code === 1006 || event?.code === 1008) {
|
||||||
|
console.log("可能是授权问题导致连接关闭,尝试重新建立连接");
|
||||||
|
|
||||||
|
// 等待一段时间后再尝试重连,避免立即重连
|
||||||
|
setTimeout(() => {
|
||||||
|
// 强制重新初始化客户端,获取最新令牌
|
||||||
|
client.value = null;
|
||||||
|
|
||||||
|
// 检查当前是否有有效令牌
|
||||||
|
const freshToken = getAccessToken();
|
||||||
|
if (freshToken) {
|
||||||
|
initializeClient();
|
||||||
|
connect();
|
||||||
|
} else {
|
||||||
|
console.warn("没有有效令牌,暂不重连WebSocket");
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 设置错误监听器
|
// 设置错误监听器
|
||||||
client.value.onStompError = (frame) => {
|
client.value.onStompError = (frame) => {
|
||||||
console.error("STOMP错误:", frame.headers, frame.body);
|
console.error("STOMP错误:", frame.headers, frame.body);
|
||||||
|
|
||||||
|
// 检查是否是授权错误
|
||||||
|
if (
|
||||||
|
frame.headers?.message?.includes("Unauthorized") ||
|
||||||
|
frame.body?.includes("Unauthorized") ||
|
||||||
|
frame.body?.includes("Token")
|
||||||
|
) {
|
||||||
|
console.warn("WebSocket授权错误,请检查登录状态");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ref, onMounted, onUnmounted, watch } from "vue";
|
import { ref, onMounted, onUnmounted, watch } from "vue";
|
||||||
import { useStomp } from "../core/useStomp";
|
import { useStomp } from "../core/useStomp";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
import { getAccessToken } from "@/utils/auth";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在线用户计数Hook
|
* 在线用户计数Hook
|
||||||
@@ -86,16 +87,35 @@ export function useOnlineCount() {
|
|||||||
const initWebSocket = () => {
|
const initWebSocket = () => {
|
||||||
if (isConnecting.value) return;
|
if (isConnecting.value) return;
|
||||||
|
|
||||||
|
// 检查是否有可用的令牌
|
||||||
|
const hasToken = !!getAccessToken();
|
||||||
|
if (!hasToken) {
|
||||||
|
console.log("没有检测到有效令牌,不尝试WebSocket连接");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
isConnecting.value = true;
|
isConnecting.value = true;
|
||||||
|
|
||||||
// 连接WebSocket
|
// 连接WebSocket
|
||||||
connect();
|
connect();
|
||||||
|
|
||||||
// 设置连接超时显示UI提示
|
// 设置连接超时显示UI提示
|
||||||
|
clearTimeout(connectionTimeoutTimer);
|
||||||
connectionTimeoutTimer = setTimeout(() => {
|
connectionTimeoutTimer = setTimeout(() => {
|
||||||
if (!isConnected.value) {
|
if (!isConnected.value) {
|
||||||
console.warn("WebSocket连接超时,将自动尝试重连");
|
console.warn("WebSocket连接超时,将自动尝试重连");
|
||||||
ElMessage.warning("正在尝试连接服务器,请稍候...");
|
ElMessage.warning("正在尝试连接服务器,请稍候...");
|
||||||
|
|
||||||
|
// 超时后尝试重新连接
|
||||||
|
closeWebSocket();
|
||||||
|
setTimeout(() => {
|
||||||
|
// 再次检查令牌有效性
|
||||||
|
if (getAccessToken()) {
|
||||||
|
initWebSocket();
|
||||||
|
} else {
|
||||||
|
console.log("令牌无效,放弃重连");
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
}
|
}
|
||||||
}, 10000); // 较长的UI提示超时
|
}, 10000); // 较长的UI提示超时
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user