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

127 lines
3.5 KiB
JavaScript
Raw Normal View History

2025-11-10 00:59:40 +08:00
import axios from 'axios'
2025-11-12 22:45:29 +08:00
import { message } from 'ant-design-vue'
import { getAuthHeader, clearAllTokens } from '@gold/utils/token-manager'
import { useUserStore } from '@/stores/user'
2025-11-10 00:59:40 +08:00
/**
* 不需要 token 的接口白名单
* 支持完整路径匹配或路径包含匹配
*/
const WHITE_LIST = [
'/auth/login', // 密码登录
'/auth/send-sms-code', // 发送验证码
'/auth/sms-login', // 短信登录
'/auth/validate-sms-code', // 验证验证码
'/auth/register', // 注册(如果有)
'/auth/reset-password', // 重置密码
'/auth/refresh-token', // 刷新token可选根据后端要求
]
/**
* 检查 URL 是否在白名单中
* @param {string} url - 请求 URL
* @returns {boolean}
*/
function isInWhiteList(url) {
if (!url) return false
return WHITE_LIST.some((path) => url.includes(path))
}
2025-11-11 23:51:17 +08:00
2025-11-10 00:59:40 +08:00
// 创建 axios 实例
const http = axios.create({
baseURL: '/',
timeout: 180000, // 3分钟
})
// 请求拦截:自动注入 Token
http.interceptors.request.use((config) => {
// 检查是否需要 token不在白名单中且未显式设置 isToken = false
const needToken = config.headers?.isToken !== false && !isInWhiteList(config.url || '')
2025-11-11 23:51:17 +08:00
config.headers['tenant-id'] = import.meta.env.VITE_TENANT_ID
2025-11-10 00:59:40 +08:00
if (needToken) {
// 使用统一的 token 管理器获取 header
const authHeader = getAuthHeader()
if (authHeader) {
config.headers.Authorization = authHeader
}
}
// 允许跨域第三方域名,使用绝对地址时保持原样
return config
})
http.interceptors.response.use(
(resp) => {
const data = resp.data
// 检查响应数据中的 code 字段
if (data && typeof data.code === 'number' && (data.code === 0 || data.code === 200)) {
return data
} else {
2025-11-12 22:45:29 +08:00
// code 不为 0 时检查是否为401
if (data && typeof data.code === 'number' && data.code === 401) {
handle401Error()
}
2025-11-10 00:59:40 +08:00
// code 不为 0 时,抛出错误
const error = new Error(data?.message || data?.msg || '请求失败')
error.code = data?.code
error.data = data
return Promise.reject(error)
}
},
(error) => {
2025-11-12 22:45:29 +08:00
// 处理 HTTP 状态码 401
if (error.response && error.response.status === 401) {
handle401Error()
}
2025-11-10 00:59:40 +08:00
// 统一错误处理:输出关键信息,便于排查 403 等问题
return Promise.reject(error)
}
)
2025-11-12 22:45:29 +08:00
/**
* 处理 401 未授权错误
* 清空 token 并退出登录
*
* 注意使用防抖机制避免多个请求同时401时重复处理
*/
function handle401Error() {
// 避免重复处理防止多个请求同时401导致多次调用
if (handle401Error.processed) {
return
}
handle401Error.processed = true
// 1. 清空所有 token
try {
clearAllTokens() // 统一使用 token-manager 的清空函数
} catch (e) {
console.error('清空 token 失败:', e)
}
// 2. 退出登录状态(清空用户信息)
try {
const userStore = useUserStore()
// logout() 会清空用户信息和本地存储
userStore.logout()
} catch (e) {
console.error('退出登录失败:', e)
}
// 3. 提示用户(延迟显示,避免在清空过程中显示)
setTimeout(() => {
message.warning('登录已过期,请重新登录', 3)
}, 100)
// 4. 延迟重置标志,避免短时间内重复处理
setTimeout(() => {
handle401Error.processed = false
}, 2000)
}
2025-11-10 00:59:40 +08:00
export default http