/** * Axios 封装 - API 请求工具 */ import axios from 'axios' import Toast from '@/components/Toast/Toast' // 创建 axios 实例 const request = axios.create({ baseURL: '/api/v1', // 使用相对路径,开发环境通过vite proxy代理,生产环境通过nginx代理 timeout: 30000, headers: { 'Content-Type': 'application/json', }, }) // 请求拦截器 request.interceptors.request.use( (config) => { // 从 localStorage 获取 token const token = localStorage.getItem('access_token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }, (error) => { return Promise.reject(error) } ) // 响应拦截器 request.interceptors.response.use( (response) => { // 如果是 blob 类型,返回完整响应(包括 headers) if (response.config.responseType === 'blob') { return response } const res = response.data // 如果返回的状态码不是 200,说明有错误 if (res.code !== 200) { Toast.error('请求失败', res.message || '请求失败') // 401: 未登录或 token 过期 if (res.code === 401) { localStorage.removeItem('access_token') localStorage.removeItem('user_info') window.location.href = '/login' } return Promise.reject(new Error(res.message || '请求失败')) } return res }, (error) => { console.error('Response error:', error) console.error('Response error detail:', error.response) if (error.response) { const { status, data } = error.response switch (status) { case 401: // 只有不在登录页时才显示Toast和跳转 if (!window.location.pathname.includes('/login')) { Toast.error('认证失败', data?.detail || '未登录或登录已过期') localStorage.removeItem('access_token') localStorage.removeItem('user_info') setTimeout(() => { window.location.href = '/login' }, 1000) // 延迟1秒,让Toast有时间显示 } break case 403: Toast.error('权限不足', data?.detail || '没有权限访问') break case 404: Toast.error('资源不存在', data?.detail || '请求的资源不存在') break case 500: Toast.error('服务器错误', data?.detail || '服务器内部错误') break default: Toast.error('请求失败', data?.detail || data?.message || '请求失败') } } else if (error.request) { Toast.error('网络错误', '请检查网络连接') } else { Toast.error('请求错误', error.message || '请求配置错误') } return Promise.reject(error) } ) export default request