fix: 🐛 修复WebSocket授权令牌验证失败导致连接断线问题

This commit is contained in:
Ray.Hao
2025-04-26 19:54:14 +08:00
parent 3deff743ad
commit 3acbf89447
2 changed files with 61 additions and 3 deletions

View File

@@ -28,10 +28,10 @@ export interface UseStompOptions {
export function useStomp(options: UseStompOptions = {}) {
// 默认值brokerURL 从环境变量中获取token 从 getAccessToken() 获取
const defaultBrokerURL = import.meta.env.VITE_APP_WS_ENDPOINT || "";
const defaultToken = getAccessToken();
// 不再使用defaultToken每次连接时直接获取最新token
const brokerURL = ref(options.brokerURL ?? defaultBrokerURL);
const token = options.token ?? defaultToken;
// 不再存储token改为在初始化时获取
const reconnectDelay = options.reconnectDelay ?? 8000;
const connectionTimeout = options.connectionTimeout ?? 10000;
const useExponentialBackoff = options.useExponentialBackoff ?? false;
@@ -60,11 +60,20 @@ export function useStomp(options: UseStompOptions = {}) {
return;
}
// 每次连接前重新获取最新令牌不依赖之前的token值
const currentToken = getAccessToken();
// 检查令牌是否为空,如果为空则不进行连接
if (!currentToken) {
console.error("WebSocket连接失败授权令牌为空请先登录");
return;
}
// 创建 STOMP 客户端
client.value = new Client({
brokerURL: brokerURL.value,
connectHeaders: {
Authorization: `Bearer ${token}`,
Authorization: `Bearer ${currentToken}`,
},
debug: options.debug ? console.log : () => {},
reconnectDelay: useExponentialBackoff ? 0 : reconnectDelay, // 使用自定义退避策略时禁用内置重连
@@ -95,11 +104,40 @@ export function useStomp(options: UseStompOptions = {}) {
client.value.onWebSocketClose = (event) => {
isConnected.value = false;
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) => {
console.error("STOMP错误:", frame.headers, frame.body);
// 检查是否是授权错误
if (
frame.headers?.message?.includes("Unauthorized") ||
frame.body?.includes("Unauthorized") ||
frame.body?.includes("Token")
) {
console.warn("WebSocket授权错误请检查登录状态");
}
};
};

View File

@@ -1,6 +1,7 @@
import { ref, onMounted, onUnmounted, watch } from "vue";
import { useStomp } from "../core/useStomp";
import { ElMessage } from "element-plus";
import { getAccessToken } from "@/utils/auth";
/**
* 在线用户计数Hook
@@ -86,16 +87,35 @@ export function useOnlineCount() {
const initWebSocket = () => {
if (isConnecting.value) return;
// 检查是否有可用的令牌
const hasToken = !!getAccessToken();
if (!hasToken) {
console.log("没有检测到有效令牌不尝试WebSocket连接");
return;
}
isConnecting.value = true;
// 连接WebSocket
connect();
// 设置连接超时显示UI提示
clearTimeout(connectionTimeoutTimer);
connectionTimeoutTimer = setTimeout(() => {
if (!isConnected.value) {
console.warn("WebSocket连接超时将自动尝试重连");
ElMessage.warning("正在尝试连接服务器,请稍候...");
// 超时后尝试重新连接
closeWebSocket();
setTimeout(() => {
// 再次检查令牌有效性
if (getAccessToken()) {
initWebSocket();
} else {
console.log("令牌无效,放弃重连");
}
}, 3000);
}
}, 10000); // 较长的UI提示超时