Files
sionrui/frontend/app/web-gold/src/api/http.js

169 lines
4.4 KiB
JavaScript
Raw Normal View History

2025-11-13 01:06:28 +08:00
/**
* 应用层 HTTP 客户端
* 使用 mono 级别的 axios 实例添加应用特定的 401 处理
*/
2025-11-12 22:45:29 +08:00
import { message } from 'ant-design-vue'
2025-11-13 01:06:28 +08:00
import { clearAllTokens, getRefreshToken } from '@gold/utils/token-manager'
2025-11-12 22:45:29 +08:00
import { useUserStore } from '@/stores/user'
2025-11-13 01:06:28 +08:00
import { createClientAxios } from '@gold/api/axios/client'
import { refreshToken } from '@/api/auth'
2025-11-10 00:59:40 +08:00
2025-11-13 01:06:28 +08:00
// 刷新 token 的状态管理
let isRefreshing = false
let refreshPromise = null
2025-11-10 00:59:40 +08:00
/**
2025-11-13 01:06:28 +08:00
* 处理 403 禁止访问错误应用层特定逻辑
* 先尝试刷新 token如果失败或没有 refresh token 才提示用户
2025-11-10 00:59:40 +08:00
*/
2025-11-13 01:06:28 +08:00
async function handleApp403Error() {
// 避免重复处理
if (handleApp403Error.processed) {
return
2025-11-10 00:59:40 +08:00
}
2025-11-13 01:06:28 +08:00
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
2025-11-12 22:45:29 +08:00
}
2025-11-13 01:06:28 +08:00
} else {
// 没有 refresh token提示用户
message.warning('登录状态已过期,请重新登录', 3)
handleApp403Error.processed = false
2025-11-12 22:45:29 +08:00
}
2025-11-13 01:06:28 +08:00
} catch (e) {
console.error('处理 403 错误失败:', e)
handleApp403Error.processed = false
2025-11-10 00:59:40 +08:00
}
2025-11-13 01:06:28 +08:00
}
2025-11-10 00:59:40 +08:00
2025-11-12 22:45:29 +08:00
/**
2025-11-13 01:06:28 +08:00
* 处理 401 未授权错误应用层特定逻辑
* 先尝试刷新 token如果失败或没有 refresh token 才退出登录
2025-11-12 22:45:29 +08:00
*/
2025-11-13 01:06:28 +08:00
async function handleApp401Error() {
// 避免重复处理
if (handleApp401Error.processed) {
2025-11-12 22:45:29 +08:00
return
}
2025-11-13 01:06:28 +08:00
handleApp401Error.processed = true
2025-11-12 22:45:29 +08:00
try {
2025-11-13 01:06:28 +08:00
// 检查是否有 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)
2025-11-12 22:45:29 +08:00
} catch (e) {
2025-11-13 01:06:28 +08:00
console.error('处理 401 错误失败:', e)
} finally {
setTimeout(() => {
handleApp401Error.processed = false
}, 2000)
2025-11-12 22:45:29 +08:00
}
}
2025-11-13 01:06:28 +08:00
/**
* 创建应用层 HTTP 客户端
* 基于 mono 级别的 axios 实例添加应用特定的错误处理
*/
const http = createClientAxios({
baseURL: '/',
timeout: 180000,
on401: handleApp401Error,
on403: handleApp403Error,
})
// 注意403 处理已在 createClientAxios 的响应拦截器中通过 on403 回调处理
2025-11-10 00:59:40 +08:00
export default http