/** * 应用层 HTTP 客户端 * 使用 mono 级别的 axios 实例,添加应用特定的 401 处理 */ import { message } from 'ant-design-vue' import { clearAllTokens, getRefreshToken } from '@gold/utils/token-manager' import { useUserStore } from '@/stores/user' import { createClientAxios } from '@gold/api/axios/client' import { refreshToken } from '@/api/auth' // 刷新 token 的状态管理 let isRefreshing = false let refreshPromise = null /** * 处理 403 禁止访问错误(应用层特定逻辑) * 先尝试刷新 token,如果失败或没有 refresh token 才提示用户 */ async function handleApp403Error() { // 避免重复处理 if (handleApp403Error.processed) { return } handleApp403Error.processed = true try { // 检查是否有 refresh token const refreshTokenValue = getRefreshToken() if (refreshTokenValue) { // 如果有 refresh token,尝试刷新 try { // 如果正在刷新,等待刷新完成 if (isRefreshing && refreshPromise) { await refreshPromise handleApp403Error.processed = false return } // 开始刷新 token isRefreshing = true refreshPromise = refreshToken() await refreshPromise // 刷新成功,重置状态 isRefreshing = false refreshPromise = null handleApp403Error.processed = false // 刷新成功,不提示用户(静默刷新) return } catch (refreshError) { // 刷新失败,清除状态 isRefreshing = false refreshPromise = null console.error('刷新 token 失败:', refreshError) // 刷新失败才提示用户 message.warning('登录状态已过期,请重新登录', 3) handleApp403Error.processed = false return } } else { // 没有 refresh token,提示用户 message.warning('登录状态已过期,请重新登录', 3) handleApp403Error.processed = false } } catch (e) { console.error('处理 403 错误失败:', e) handleApp403Error.processed = false } } /** * 处理 401 未授权错误(应用层特定逻辑) * 先尝试刷新 token,如果失败或没有 refresh token 才退出登录 */ async function handleApp401Error() { // 避免重复处理 if (handleApp401Error.processed) { return } handleApp401Error.processed = true try { // 检查是否有 refresh token const refreshTokenValue = getRefreshToken() if (refreshTokenValue) { // 如果有 refresh token,尝试刷新 try { // 如果正在刷新,等待刷新完成 if (isRefreshing && refreshPromise) { await refreshPromise handleApp401Error.processed = false return } // 开始刷新 token isRefreshing = true refreshPromise = refreshToken() await refreshPromise // 刷新成功,重置状态 isRefreshing = false refreshPromise = null handleApp401Error.processed = false // 刷新成功,不提示用户(静默刷新) return } catch (refreshError) { // 刷新失败,清除状态 isRefreshing = false refreshPromise = null console.error('刷新 token 失败:', refreshError) // 继续执行退出登录逻辑 } } // 没有 refresh token 或刷新失败,执行退出登录 try { clearAllTokens() } catch (e) { console.error('清空 token 失败:', e) } try { const userStore = useUserStore() userStore.logout() } catch (e) { console.error('退出登录失败:', e) } setTimeout(() => { message.warning('登录已过期,请重新登录', 3) }, 100) } catch (e) { console.error('处理 401 错误失败:', e) } finally { setTimeout(() => { handleApp401Error.processed = false }, 2000) } } /** * 创建应用层 HTTP 客户端 * 基于 mono 级别的 axios 实例,添加应用特定的错误处理 */ const http = createClientAxios({ baseURL: '/', timeout: 180000, on401: handleApp401Error, on403: handleApp403Error, }) // 注意:403 处理已在 createClientAxios 的响应拦截器中通过 on403 回调处理 export default http