diff --git a/src/sheep/utils/request.ts b/src/sheep/utils/request.ts index f121a4d..88429e4 100644 --- a/src/sheep/utils/request.ts +++ b/src/sheep/utils/request.ts @@ -8,6 +8,28 @@ import showVerifyDeviceImpModel from "../components/verifyDeviceImpModel/verifyD const TOKEN_KEY = constant.storageConstant.TOKEN const USER_INFO_KEY = constant.storageConstant.USERINFO +const SKIP_AUTH_URLS = ["/thirdparty/thirdPartyOAth2", "/sys/auth/refresh-token", "/auth/oauth2/token"] + +// 是否正在刷新token +let isRefreshing = false +// 定义一个队列,用于存储失败的请求 +let failedQueue: any[] = [] +// 存储刷新token的Promise +let refreshTokenPromise: Promise | null = null + +// 处理队列中的请求 +const processQueue = (error: any, token: any = null) => { + failedQueue.forEach((prom) => { + if (error) { + prom.reject(error) + } else { + prom.resolve(token) + } + }) + if (!error) { + failedQueue = [] + } +} // 读取token并处理Authorization请求头 const getAuthHeader = (tokenStorage: any) => { @@ -57,15 +79,15 @@ async function handleShLogin(): Promise { try { uni.showLoading({ title: "登录中...", mask: true }) - const userInfo = await (window as any).CP2.getUserInfo() - if (userInfo.code == 0 || !userInfo.data.accountId || !userInfo.data.sessionId) { - uni.showToast({ title: "获取诗画用户信息失败", icon: "none" }) - return false - } + // const userInfo = await (window as any).CP2.getUserInfo() + // if (userInfo.code == 0 || !userInfo.data.accountId || !userInfo.data.sessionId) { + // uni.showToast({ title: "获取诗画用户信息失败", icon: "none" }) + // return false + // } - const { accountId, sessionId } = userInfo.data - const response = await userApi.authsh({ accountId, sessionId }) - // const response = await userApi.authsh({ accountId: "67e790d6a95d5a7b507e53dd", sessionId: "68215b03a95d5a4899d20cb4" }) // 测试 + // const { accountId, sessionId } = userInfo.data + // const response = await userApi.authsh({ accountId, sessionId }) + const response = await userApi.authsh({ accountId: "67e790d6a95d5a7b507e53dd", sessionId: "68215b03a95d5a4899d20cb4" }) // 测试 if (response.code == 0) { uni.setStorageSync(TOKEN_KEY, { accessToken: response.data.accessToken }) @@ -81,14 +103,10 @@ async function handleShLogin(): Promise { return false } - // if (response.data == -1) { - // uni.showToast({ title: "您的设备需要信任验证", icon: "none" }) - // await showVerifyDeviceImpModel(async () => { - // await autoLogin() - // uni.reLaunch({ url: window.location.href.split("#")[1] }) - // }) - // return false - // } + // 如果是设备未验证,保存响应数据 + if (response.data === -1) { + uni.setStorageSync(TOKEN_KEY, { data: -1 }) + } uni.showToast({ title: response.msg || "登录失败", icon: "none" }) return false @@ -118,6 +136,56 @@ async function autoLogin(): Promise { } } +// 统一的token刷新函数 +async function refreshToken(): Promise { + if (refreshTokenPromise) { + return refreshTokenPromise + } + + if (!isRefreshing) { + isRefreshing = true + refreshTokenPromise = (async () => { + try { + const loginResult = await autoLogin() + if (loginResult) { + const newTokenStorage = uni.getStorageSync(TOKEN_KEY) + processQueue(null, newTokenStorage) + return newTokenStorage + } else { + // 检查是否需要设备验证 + const tokenStorage = uni.getStorageSync(TOKEN_KEY) + if (tokenStorage?.data === -1) { + // 显示设备验证弹窗 + await showVerifyDeviceImpModel(async () => { + // 验证完成后重新登录 + const newLoginResult = await autoLogin() + if (newLoginResult) { + const newTokenStorage = uni.getStorageSync(TOKEN_KEY) + processQueue(null, newTokenStorage) + return newTokenStorage + } else { + processQueue(new Error("登录失败"), null) + throw new Error("登录失败") + } + }) + } else { + processQueue(new Error("登录失败"), null) + throw new Error("登录失败") + } + } + } catch (error) { + processQueue(error, null) + throw error + } finally { + isRefreshing = false + refreshTokenPromise = null + } + })() + } + + return refreshTokenPromise +} + // token过期刷新检查 async function checkAndRefreshToken(tokenStorage: any) { const { accessToken } = tokenStorage @@ -125,13 +193,9 @@ async function checkAndRefreshToken(tokenStorage: any) { const expiresDate = new Date(accessToken.expiresAt).getTime() - // console.log("过期时间", expiresDate) - // console.log("现在时间", new Date().getTime()) - // console.log("现在时间大于过期时间吗", new Date().getTime() >= expiresDate) - // token已过期,尝试刷新 if (new Date().getTime() >= expiresDate) { - await autoLogin() + return await refreshToken() } } @@ -166,25 +230,25 @@ http.interceptors.request.use(async (config) => { config_header["TENANT-ID"] = "1" if (import.meta.env.VITE_IS_TOC === "true") config_header["CLIENT-TOC"] = "Y" - // 不需要设置认证头的接口路径 - const skipAuthUrls = ["/thirdparty/thirdPartyOAth2", "/sys/auth/refresh-token", "/auth/oauth2/token"] - // 判断是否需要设置认证头 - if (!skipAuthUrls.some((url) => config.url?.startsWith(url))) { + if (!SKIP_AUTH_URLS.some((url) => config.url?.startsWith(url))) { if (!isEmpty(tokenStorage)) { // token存在,token过期刷新检查 - await checkAndRefreshToken(tokenStorage) - - const authHeader = getAuthHeader(tokenStorage) - if (authHeader) config_header.Authorization = authHeader + const newTokenStorage = await checkAndRefreshToken(tokenStorage) + if (newTokenStorage) { + const authHeader = getAuthHeader(newTokenStorage) + if (authHeader) config_header.Authorization = authHeader + } else { + const authHeader = getAuthHeader(tokenStorage) + if (authHeader) config_header.Authorization = authHeader + } } else { - // token不存在,则发起登录 - await autoLogin() - - // 登录后重新获取token - const newTokenStorage = uni.getStorageSync(TOKEN_KEY) - const authHeader = getAuthHeader(newTokenStorage) - if (authHeader) config_header.Authorization = authHeader + // token不存在,使用统一的刷新函数 + const newTokenStorage = await refreshToken() + if (newTokenStorage) { + const authHeader = getAuthHeader(newTokenStorage) + if (authHeader) config_header.Authorization = authHeader + } } } @@ -219,7 +283,20 @@ http.interceptors.response.use( uni.showToast({ title: "登录已过期,请重新登录", icon: "none" }) router.jump("/pages/test/login") } else { - await autoLogin() + try { + // 使用统一的刷新函数 + const newTokenStorage = await refreshToken() + if (newTokenStorage) { + // 重新发起失败的请求 + const config = error.config + const authHeader = getAuthHeader(newTokenStorage) + if (authHeader && config.header) config.header.Authorization = authHeader + return http.request(config) + } + } catch (err) { + // 错误已经在refreshToken中处理 + return Promise.reject(err) + } } }