import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; import envConfig from '../../env'; import Cookies from 'js-cookie'; import utils from '../lib/utils'; const API_BASE_URL = envConfig.baseURL; const message = utils.message; // 使用全局 message const api = axios.create({ baseURL: API_BASE_URL, timeout: 100000, headers: { 'Content-Type': 'application/json', }, withCredentials: true, }); // 请求拦截器 api.interceptors.request.use( (config: InternalAxiosRequestConfig) => { const token = localStorage.getItem('token'); if (token && config.headers) { config.headers['Authorization'] = `Bearer ${token}`; } return config; }, (error: AxiosError) => { return Promise.reject(error); } ); // 🔥 全局唯一锁:保证并发多个 401 也只执行一次 let isLoggingOut = false; const handleLogoutAndRedirect = () => { // 已经在登出流程中,直接阻止 if (isLoggingOut) return; // 立即上锁 isLoggingOut = true; // 清除登录信息 try { localStorage.clear(); Cookies.remove('userId'); Cookies.remove('Admin-Token'); Cookies.remove('token'); } catch { } // redux 登出 import('../store').then(storeModule => { import('../store/userSlice').then(({ logout }) => { storeModule.default.dispatch(logout()); }); }); // 只提示一次 message?.error('登录已过期,请重新登录'); // 只跳转一次 setTimeout(() => { window.location.href = '/login'; }, 800); }; // 响应拦截器 api.interceptors.response.use( (response: AxiosResponse) => { const data = response.data; // 业务 401 → 统一走登出 if (data?.code === 401) { handleLogoutAndRedirect(); return Promise.reject(new Error('登录已过期')); } return data; }, (error: AxiosError) => { // HTTP 401 → 统一走登出 if (error.response?.status == 401) { handleLogoutAndRedirect(); return Promise.reject(error); } // 网络异常 if (!error.response) { message?.error('网络异常,请稍后重试'); return Promise.reject(error); } return Promise.reject(error); } ); export default api;