snack-mall/admin-snack/src/utils/request.ts

91 lines
2.1 KiB
TypeScript

import axios, {
type AxiosInstance,
type AxiosRequestConfig,
type AxiosResponse,
type InternalAxiosRequestConfig
} from 'axios'
import { ElMessage } from 'element-plus'
import NProgress from 'nprogress'
import { useUserStore } from '@/stores/modules/user'
NProgress.configure({ showSpinner: false })
/**
* 后端统一响应结构
*/
export interface ApiResponse<T = unknown> {
code: number
message: string
data: T
}
const service: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 15000,
withCredentials: false
})
// 请求拦截器
service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
NProgress.start()
const userStore = useUserStore()
if (userStore.token) {
config.headers.Authorization = `Bearer ${userStore.token}`
}
return config
},
(error) => {
NProgress.done()
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
(response: AxiosResponse<ApiResponse>) => {
NProgress.done()
const { code, message, data } = response.data
if (code === 200) {
return data as any
}
ElMessage.error(message || '请求失败')
return Promise.reject(new Error(message || 'Error'))
},
(error) => {
NProgress.done()
const status = error.response?.status
let message = error.message
if (status === 401) {
message = '登录已过期,请重新登录'
const userStore = useUserStore()
userStore.clearAuth()
// 避免循环依赖,使用 import() 动态加载
import('@/router').then(({ default: router }) => {
router.push('/login')
})
} else if (status === 403) {
message = '无权限访问'
} else if (status === 404) {
message = '资源不存在'
} else if (status === 500) {
message = '服务器内部错误'
}
ElMessage.error(message)
return Promise.reject(error)
}
)
/**
* 统一请求方法封装
*/
export function request<T = unknown>(config: AxiosRequestConfig): Promise<T> {
return service.request<unknown, T>(config)
}
export default service