55 lines
1.4 KiB
TypeScript
55 lines
1.4 KiB
TypeScript
/**
|
||
* Axios 实例配置
|
||
* 全局拦截 401/403 响应,自动跳转登录页
|
||
*/
|
||
import axios from 'axios';
|
||
|
||
// 动态获取 API 地址:服务端使用 localhost,客户端使用当前域名
|
||
const API_BASE = typeof window === 'undefined'
|
||
? 'http://localhost:8006'
|
||
: '';
|
||
|
||
// 防止重复跳转
|
||
let isRedirecting = false;
|
||
|
||
const PUBLIC_PATHS = new Set(['/login', '/register']);
|
||
|
||
// 创建 axios 实例
|
||
const api = axios.create({
|
||
baseURL: API_BASE,
|
||
withCredentials: true, // 自动携带 cookie
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
});
|
||
|
||
// 响应拦截器 - 全局处理 401/403
|
||
api.interceptors.response.use(
|
||
(response) => response,
|
||
async (error) => {
|
||
const status = error.response?.status;
|
||
|
||
const isPublicPath = typeof window !== 'undefined' && PUBLIC_PATHS.has(window.location.pathname);
|
||
|
||
if ((status === 401 || status === 403) && !isRedirecting && !isPublicPath) {
|
||
isRedirecting = true;
|
||
|
||
// 调用 logout API 清除 HttpOnly cookie
|
||
try {
|
||
await fetch('/api/auth/logout', { method: 'POST' });
|
||
} catch (e) {
|
||
// 忽略错误
|
||
}
|
||
|
||
// 跳转登录页
|
||
if (typeof window !== 'undefined') {
|
||
window.location.replace('/login');
|
||
}
|
||
}
|
||
|
||
return Promise.reject(error);
|
||
}
|
||
);
|
||
|
||
export default api;
|