fix: 🐛 修复WebSocket授权令牌验证失败导致连接断线问题
This commit is contained in:
@@ -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授权错误,请检查登录状态");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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提示超时
|
||||
|
||||
|
||||
Reference in New Issue
Block a user