Files
yunzerwebsiteallinone/backend/src/utils/request.js
T
2026-09-19 21:44:04 +08:00

94 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;