139 lines
4.1 KiB
TypeScript
139 lines
4.1 KiB
TypeScript
import axios from 'axios'
|
|
|
|
// http状态码
|
|
import { errorCodeType } from './errorCodeType'
|
|
// 语言管理器
|
|
import { generateAcceptLanguageHeader } from '@/utils/language'
|
|
// 路由
|
|
import router from '@/router'
|
|
|
|
const envUrl = import.meta.env.VITE_API_BASE_URL
|
|
console.log('API Base URL:', envUrl)
|
|
|
|
// 防止重复跳转到登录页的标志
|
|
let isRedirectingToLogin = false
|
|
|
|
// 清除用户认证信息的函数
|
|
const clearAuthInfo = () => {
|
|
localStorage.removeItem('token')
|
|
// 清除其他可能的认证信息
|
|
localStorage.removeItem('userInfo')
|
|
localStorage.removeItem('refreshToken')
|
|
}
|
|
|
|
// 跳转到登录页的函数
|
|
|
|
const redirectToLogin=()=> {
|
|
if (!isRedirectingToLogin) {
|
|
isRedirectingToLogin = true
|
|
|
|
// 立即清除认证信息
|
|
clearAuthInfo()
|
|
|
|
// 检查当前路径
|
|
const currentPath = router.currentRoute.value?.path
|
|
if (currentPath === '/login') {
|
|
isRedirectingToLogin = false
|
|
return
|
|
}
|
|
|
|
// 跳转到登录页
|
|
setTimeout(() => {
|
|
router.replace('/login').finally(() => {
|
|
setTimeout(() => {
|
|
isRedirectingToLogin = false
|
|
}, 1000)
|
|
})
|
|
}, 50)
|
|
}
|
|
}
|
|
|
|
//使用create方法创建axios实例
|
|
const Axios = axios.create({
|
|
timeout: 10000, // 请求超时时间
|
|
baseURL: envUrl,
|
|
headers: {
|
|
'Content-Type': 'application/json;charset=UTF-8',
|
|
},
|
|
// 跨域时候允许携带凭证 (开发环境不启用,避免CORS问题)
|
|
withCredentials: false
|
|
})
|
|
// 添加请求拦截器
|
|
Axios.interceptors.request.use(config => {
|
|
const token = localStorage.getItem('token')
|
|
// 自定义请求头携带token (Bearer认证)
|
|
if(token){
|
|
config.headers['Authorization'] = `Bearer ${token}`
|
|
}
|
|
|
|
// 设置 Accept-Language 头,符合 RFC 7231 规范
|
|
// 优先级:用户选择;q=1.0 > 备用语言;q=0.8 > 通配符;q=0.5
|
|
config.headers['Accept-Language'] = generateAcceptLanguageHeader()
|
|
|
|
return config
|
|
})
|
|
// 添加响应拦截器
|
|
Axios.interceptors.response.use(response => {
|
|
// 处理文件下载等二进制响应
|
|
if (response.config?.responseType === 'blob') {
|
|
return response
|
|
}
|
|
|
|
const apiData = response.data as any
|
|
// 这个 Code 是和后端约定的业务 Code
|
|
const code = apiData.code
|
|
// 如果没有 Code, 代表这不是项目后端开发的 API
|
|
if (code === undefined) {
|
|
// 不在拦截器中显示错误,让组件自己处理
|
|
return Promise.reject(new Error("非本系统的接口"))
|
|
} else {
|
|
switch (code) {
|
|
case '000000':
|
|
// code === '000000' 代表成功
|
|
return apiData
|
|
case 401:
|
|
// code === 401 代表未授权,清除token并跳转到登录页
|
|
redirectToLogin()
|
|
const authError = new Error(apiData.message || "未授权访问")
|
|
;(authError as any).response = { data: apiData }
|
|
return Promise.reject(authError)
|
|
default:
|
|
// 不在拦截器中显示错误,让组件自己处理
|
|
// 将错误信息附加到 Error 对象上,供组件使用
|
|
const error = new Error(apiData.message || "Error")
|
|
;(error as any).response = { data: apiData }
|
|
return Promise.reject(error)
|
|
}
|
|
}
|
|
}, error => {
|
|
console.log('Response的error', error)
|
|
// 不在拦截器中显示错误消息,让具体的页面组件处理
|
|
// showErrMessage(errorCodeType(error.response?.status))
|
|
|
|
// 为错误对象添加更多信息,便于组件处理
|
|
if (error.response) {
|
|
const status = error.response.status
|
|
const data = error.response.data
|
|
|
|
// 处理HTTP 401状态码
|
|
if (status === 401) {
|
|
redirectToLogin();
|
|
(error as any).backendMessage = data.message || "未授权访问"
|
|
return Promise.reject(error)
|
|
}
|
|
|
|
// 如果后端返回了错误消息,优先使用后端消息
|
|
if (data && data.message) {
|
|
;(error as any).backendMessage = data.message
|
|
} else {
|
|
// 否则使用状态码对应的消息
|
|
;(error as any).backendMessage = errorCodeType(status)
|
|
}
|
|
}
|
|
|
|
return Promise.reject(error)
|
|
})
|
|
|
|
// 错误处理函数已移除,由页面组件统一处理错误显示
|
|
|
|
export default Axios; |