import axios from 'axios'; import { message } from 'antd'; import { getRequestErrorMessage, isAuthSessionFailure } from './authSessionPolicy'; import { requestDesktopSessionRenewal } from '../utils/desktopEmbedSession'; const DEFAULT_REQUEST_TIMEOUT_MS = Math.max( Number(import.meta.env.VITE_API_REQUEST_TIMEOUT_MS) || 120000, 15000 ); const request = axios.create({ baseURL: '', // Proxy handles the base URL timeout: DEFAULT_REQUEST_TIMEOUT_MS, }); const AUTH_USER_STORAGE_KEY = 'auth_user'; function clearAuthSession() { localStorage.removeItem('token'); localStorage.removeItem(AUTH_USER_STORAGE_KEY); } function parseJwtPayload(token) { if (!token) { return null; } try { const [, payload] = token.split('.'); if (!payload) { return null; } const normalized = payload.replace(/-/g, '+').replace(/_/g, '/'); const padded = normalized.padEnd(normalized.length + ((4 - normalized.length % 4) % 4), '='); return JSON.parse(window.atob(padded)); } catch { return null; } } function isLocalPreviewSession() { const isLocalHost = ['localhost', '127.0.0.1'].includes(window.location.hostname); if (!isLocalHost) { return false; } const payload = parseJwtPayload(localStorage.getItem('token')); return payload?.authSource === 'local-preview'; } function isPublicAuthPage() { return ['/login', '/callback', '/install'].includes(window.location.pathname); } function shouldBypass401Redirect(error) { const url = error?.config?.url || ''; return url.includes('/api/auth/verify') || isLocalPreviewSession(); } // Request interceptor request.interceptors.request.use( (config) => { const token = localStorage.getItem('token'); if (token) { config.headers['Authorization'] = `Bearer ${token}`; } return config; }, (error) => { return Promise.reject(error); } ); // Response interceptor request.interceptors.response.use( (response) => { const res = response.data; // Compatible with backend interfaces that don't return code if (res && res.code && res.code !== 200) { const shouldBypassRedirect = res.code === 401 && shouldBypass401Redirect(response); if (!shouldBypassRedirect && !response.config?.silentError) { message.error(res.message || 'Error'); } if (res.code === 401 && !shouldBypassRedirect) { // Handle unauthorized - 但如果已在登录页则不重定向 clearAuthSession(); if (!isPublicAuthPage()) { if (!requestDesktopSessionRenewal('api-unauthorized')) { window.location.href = '/login'; } } } return Promise.reject(new Error(res.message || 'Error')); } return res; }, (error) => { const authSessionFailure = isAuthSessionFailure(error.response); if (!authSessionFailure && !error.config?.silentError) { message.error(getRequestErrorMessage(error)); } if (authSessionFailure && !shouldBypass401Redirect(error)) { clearAuthSession(); // 如果已在登录页则不重定向,避免无限循环 if (!isPublicAuthPage()) { if (!requestDesktopSessionRenewal('api-unauthorized')) { window.location.href = '/login'; } } } return Promise.reject(error); } ); export default request;