import axios from 'axios'; import { isSSOEnabled, refreshAccessToken, clearTokens } from '@/utils/authClient'; // 获取API基础URL,添加调试信息 const apiBaseURL = import.meta.env.VITE_API_BASE_URL; // 创建axios实例(普通接口 5min;大文件上传在 api/file.js 单独设置更长 timeout) const service = axios.create({ baseURL: apiBaseURL, timeout: 300000, withCredentials: false // JWT 不需要 Cookie }); // 请求拦截器 service.interceptors.request.use( config => { const token = localStorage.getItem('token'); if (token) { config.headers['Authorization'] = `Bearer ${token}`; } // 对于有 body 的请求(POST、PUT、PATCH),默认 JSON; // FormData 必须由浏览器自行设置 Content-Type,否则缺少 multipart boundary,服务端无法解析 if (config.data && ['post', 'put', 'patch'].includes(config.method?.toLowerCase())) { if (typeof FormData !== 'undefined' && config.data instanceof FormData) { delete config.headers['Content-Type']; delete config.headers['content-type']; } else if (!config.headers['Content-Type'] && !config.headers['content-type']) { config.headers['Content-Type'] = 'application/json'; } } return config; }, error => { return Promise.reject(error); } ); // 响应拦截器 service.interceptors.response.use( response => { return response.data; }, async error => { if (error.response) { // 后端统一返回 {code, msg},优先透出业务提示(如唯一性冲突、无权操作), // 避免页面只显示 "Request failed with status code xxx" const bizMsg = error.response.data?.msg || error.response.data?.message; switch (error.response.status) { case 401: // 统一认证模式:先用 refresh_token 静默换取新令牌并重放原请求, // 刷新失败(令牌过期/被吊销)才真正登出。 if (isSSOEnabled()) { try { const newToken = await refreshAccessToken(); error.config.headers['Authorization'] = `Bearer ${newToken}`; return service.request(error.config); } catch (e) { clearTokens(); localStorage.removeItem('userInfo'); window.location.href = '#/login'; return Promise.reject(new Error('token无效')); } } console.error('未授权,请重新登录'); localStorage.removeItem('token'); localStorage.removeItem('userInfo'); if (window.location.hash !== '#/login') { window.location.href = '#/login'; } return Promise.reject(new Error('token无效')); case 404: console.error('请求的资源不存在'); break; default: console.error('请求失败,请稍后再试'); } if (bizMsg) { return Promise.reject(new Error(bizMsg)); } } else if (error.request) { if (error.code === 'ECONNABORTED') { console.error('请求超时,请稍后重试'); } else { console.error('请求失败,请检查网络连接'); } } else { console.error('请求配置错误'); } return Promise.reject(error); } ); export default service;