feat: 前端优化
This commit is contained in:
@@ -28,6 +28,32 @@ function isInWhiteList(url) {
|
||||
return WHITE_LIST.some((path) => url.includes(path))
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动刷新 token 的锁机制和队列
|
||||
*/
|
||||
let isRefreshing = false
|
||||
let refreshSubscribers = []
|
||||
|
||||
/**
|
||||
* 订阅 token 刷新完成
|
||||
* @param {Function} callback - 回调函数
|
||||
*/
|
||||
function subscribeTokenRefresh(callback) {
|
||||
if (isRefreshing) {
|
||||
refreshSubscribers.push(callback)
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行所有订阅回调
|
||||
*/
|
||||
function onRefreshed() {
|
||||
refreshSubscribers.forEach(callback => callback())
|
||||
refreshSubscribers = []
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 401 未授权错误
|
||||
* 注意:只做清理工作,不处理重定向(重定向由上层回调处理)
|
||||
@@ -59,6 +85,7 @@ function handle401Error(error) {
|
||||
* @param {number} options.timeout - 超时时间(毫秒)
|
||||
* @param {Function} options.on401 - 401 错误处理函数
|
||||
* @param {Function} options.on403 - 403 错误处理函数
|
||||
* @param {Function} options.refreshTokenFn - Token 刷新函数(可选)
|
||||
* @returns {AxiosInstance} Axios 实例
|
||||
*/
|
||||
export function createClientAxios(options = {}) {
|
||||
@@ -67,6 +94,7 @@ export function createClientAxios(options = {}) {
|
||||
timeout = 180000,
|
||||
on401 = handle401Error,
|
||||
on403 = null,
|
||||
refreshTokenFn = null,
|
||||
} = options
|
||||
|
||||
const client = axios.create({
|
||||
@@ -77,21 +105,74 @@ export function createClientAxios(options = {}) {
|
||||
// 请求拦截器
|
||||
client.interceptors.request.use((config) => {
|
||||
// 添加 tenant-id
|
||||
const tenantId =
|
||||
const tenantId =
|
||||
(typeof import.meta !== 'undefined' && import.meta.env?.VITE_TENANT_ID) ||
|
||||
(typeof process !== 'undefined' && process.env?.VITE_TENANT_ID) ||
|
||||
'1'
|
||||
|
||||
|
||||
if (tenantId) {
|
||||
config.headers['tenant-id'] = tenantId
|
||||
}
|
||||
|
||||
// 添加 Authorization header
|
||||
// 检查是否需要认证
|
||||
const needToken = config.headers?.isToken !== false && !isInWhiteList(config.url || '')
|
||||
|
||||
if (needToken) {
|
||||
const authHeader = tokenManager.getAuthHeader()
|
||||
if (authHeader) {
|
||||
config.headers.Authorization = authHeader
|
||||
// 检查 token 是否即将过期(30秒缓冲)
|
||||
const BUFFER_TIME = 30 * 1000
|
||||
const currentToken = tokenManager.getAccessToken()
|
||||
|
||||
if (!currentToken) {
|
||||
console.warn('[Token] 没有可用的 accessToken')
|
||||
return config
|
||||
}
|
||||
|
||||
const isTokenExpired = tokenManager.isExpired(BUFFER_TIME)
|
||||
|
||||
if (isTokenExpired) {
|
||||
console.info('[Token] Token刷新')
|
||||
|
||||
// 如果不在刷新过程中,启动刷新
|
||||
if (!isRefreshing) {
|
||||
isRefreshing = true
|
||||
|
||||
// 执行刷新(使用上层传入的刷新函数)
|
||||
if (refreshTokenFn && typeof refreshTokenFn === 'function') {
|
||||
refreshTokenFn()
|
||||
.then(() => {
|
||||
console.info('[Token] 刷新成功')
|
||||
isRefreshing = false
|
||||
onRefreshed()
|
||||
})
|
||||
.catch((error) => {
|
||||
isRefreshing = false
|
||||
onRefreshed()
|
||||
console.error('[Token] 刷新失败:', error.message)
|
||||
})
|
||||
} else {
|
||||
console.warn('[Token] 未提供刷新函数,跳过刷新')
|
||||
isRefreshing = false
|
||||
onRefreshed()
|
||||
}
|
||||
}
|
||||
|
||||
// 等待刷新完成
|
||||
return new Promise((resolve) => {
|
||||
subscribeTokenRefresh(() => {
|
||||
// 刷新完成后,重新获取 token 并添加到请求头
|
||||
const authHeader = tokenManager.getAuthHeader()
|
||||
if (authHeader) {
|
||||
config.headers.Authorization = authHeader
|
||||
}
|
||||
resolve(config)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// Token 未过期,直接添加 Authorization 头
|
||||
const authHeader = tokenManager.getAuthHeader()
|
||||
if (authHeader) {
|
||||
config.headers.Authorization = authHeader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user