152 lines
4.2 KiB
TypeScript
152 lines
4.2 KiB
TypeScript
import { refreshAuthToken, isTokenExpiringSoon, clearToken } from './utils';
|
||
|
||
// Token过期处理
|
||
export const handleTokenExpired = () => {
|
||
if (typeof window !== 'undefined') {
|
||
// 清除本地存储
|
||
clearToken();
|
||
|
||
// 跳转到登录页面
|
||
setTimeout(() => {
|
||
window.location.href = '/login';
|
||
}, 0);
|
||
}
|
||
};
|
||
|
||
// 显示API错误,但不会重定向
|
||
export const showApiError = (error: any, defaultMessage: string = '请求失败') => {
|
||
if (typeof window === 'undefined') return; // 服务端不处理
|
||
|
||
let errorMessage = defaultMessage;
|
||
|
||
// 尝试从各种可能的错误格式中获取消息
|
||
if (error) {
|
||
if (typeof error === 'string') {
|
||
errorMessage = error;
|
||
} else if (error instanceof Error) {
|
||
errorMessage = error.message || defaultMessage;
|
||
} else if (typeof error === 'object') {
|
||
// 尝试从API响应中获取错误消息
|
||
errorMessage = error.msg || error.message || error.error || defaultMessage;
|
||
}
|
||
}
|
||
|
||
// 显示错误消息
|
||
console.error('API错误:', errorMessage);
|
||
|
||
// 这里可以集成toast系统
|
||
// 由于toast context在组件层级,这里暂时用console
|
||
// 实际项目中可以通过事件系统或其他方式集成
|
||
};
|
||
|
||
// 请求拦截器 - 检查token是否需要刷新
|
||
export const requestInterceptor = async (): Promise<boolean> => {
|
||
if (typeof window === 'undefined') {
|
||
return true;
|
||
}
|
||
|
||
// 检查token是否即将过期
|
||
if (isTokenExpiringSoon()) {
|
||
try {
|
||
console.log('Token即将过期,尝试刷新...');
|
||
const success = await refreshAuthToken();
|
||
if (!success) {
|
||
console.log('Token刷新失败,需要重新登录');
|
||
handleTokenExpired();
|
||
return false;
|
||
}
|
||
console.log('Token刷新成功');
|
||
} catch (error) {
|
||
console.error('Token刷新过程中出错:', error);
|
||
handleTokenExpired();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
// 响应拦截器 - 处理常见错误
|
||
export const responseInterceptor = (response: any, result: any) => {
|
||
// 处理401未授权
|
||
if (response?.status === 401 || (result && result.code === 401)) {
|
||
handleTokenExpired();
|
||
throw new Error('登录已过期,请重新登录');
|
||
}
|
||
|
||
// 处理403禁止访问
|
||
if (response?.status === 403 || (result && result.code === 403)) {
|
||
throw new Error('没有权限访问此资源');
|
||
}
|
||
|
||
// 处理404未找到
|
||
if (response?.status === 404 || (result && result.code === 404)) {
|
||
throw new Error('请求的资源不存在');
|
||
}
|
||
|
||
// 处理500服务器错误
|
||
if (response?.status >= 500 || (result && result.code >= 500)) {
|
||
throw new Error('服务器内部错误,请稍后重试');
|
||
}
|
||
|
||
return result;
|
||
};
|
||
|
||
// 错误拦截器 - 统一错误处理
|
||
export const errorInterceptor = (error: any) => {
|
||
console.error('API请求错误:', error);
|
||
|
||
let errorMessage = '网络请求失败,请稍后重试';
|
||
|
||
if (error) {
|
||
if (typeof error === 'string') {
|
||
errorMessage = error;
|
||
} else if (error instanceof Error) {
|
||
errorMessage = error.message;
|
||
} else if (error.name === 'TypeError' && error.message.includes('fetch')) {
|
||
errorMessage = '网络连接失败,请检查网络设置';
|
||
} else if (error.name === 'AbortError') {
|
||
errorMessage = '请求已取消';
|
||
}
|
||
}
|
||
|
||
showApiError(error, errorMessage);
|
||
throw new Error(errorMessage);
|
||
};
|
||
|
||
// 网络状态监听
|
||
export const setupNetworkListener = () => {
|
||
if (typeof window === 'undefined') return;
|
||
|
||
const handleOnline = () => {
|
||
console.log('网络已连接');
|
||
// 可以在这里添加网络恢复后的处理逻辑
|
||
};
|
||
|
||
const handleOffline = () => {
|
||
console.log('网络已断开');
|
||
showApiError(null, '网络连接已断开,请检查网络设置');
|
||
};
|
||
|
||
window.addEventListener('online', handleOnline);
|
||
window.addEventListener('offline', handleOffline);
|
||
|
||
// 返回清理函数
|
||
return () => {
|
||
window.removeEventListener('online', handleOnline);
|
||
window.removeEventListener('offline', handleOffline);
|
||
};
|
||
};
|
||
|
||
// 初始化拦截器
|
||
export const initInterceptors = () => {
|
||
// 设置网络监听
|
||
const cleanupNetwork = setupNetworkListener();
|
||
|
||
// 返回清理函数
|
||
return () => {
|
||
if (cleanupNetwork) {
|
||
cleanupNetwork();
|
||
}
|
||
};
|
||
};
|