Files
web-Iot/src/api/request.ts
2026-08-12 11:29:44 +08:00

104 lines
2.3 KiB
TypeScript
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, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import envConfig from '../../env';
import Cookies from 'js-cookie';
import utils from '../lib/utils';
import i18n from '../i18n';
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}`;
}
if (!(config.data instanceof FormData)) {
config.headers['Content-Type'] = 'application/json';
} else {
// FormData 删除json头,交给axios自动生成multipart
delete config.headers['Content-Type'];
}
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(i18n.t('api.loginExpired'));
// 只跳转一次
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(i18n.t('api.loginExpired')));
}
return data;
},
(error: AxiosError) => {
// HTTP 401 → 统一走登出
if (error.response?.status == 401) {
handleLogoutAndRedirect();
return Promise.reject(error);
}
// 网络异常
if (!error.response) {
message?.error(i18n.t('api.networkError'));
return Promise.reject(error);
}
return Promise.reject(error);
}
);
export default api;