gongxiangp2/lib/error-handler.ts

207 lines
5.4 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 { DownloadErrorCode, parseDownloadError, DownloadErrorMessages } from './download-errors';
/**
* API错误响应接口
*/
export interface ApiErrorResponse {
error?: string;
code?: string;
details?: string;
message?: string;
}
/**
* 通用错误类型
*/
export enum ErrorType {
// 下载错误
DOWNLOAD = 'DOWNLOAD',
// 上传错误
UPLOAD = 'UPLOAD',
// 网络错误
NETWORK = 'NETWORK',
// 权限错误
PERMISSION = 'PERMISSION',
// 验证错误
VALIDATION = 'VALIDATION',
// 服务器错误
SERVER = 'SERVER',
// 未知错误
UNKNOWN = 'UNKNOWN',
}
/**
* 解析API错误响应
*/
export function parseApiError(error: any): {
type: ErrorType;
message: string;
code?: string;
details?: string;
} {
// 如果已经是解析后的格式
if (error?.type && error?.message) {
return error;
}
// 如果是下载错误(有DownloadErrorCode)
if (error?.code && Object.values(DownloadErrorCode).includes(error.code as DownloadErrorCode)) {
const parsed = parseDownloadError(error);
return {
type: ErrorType.DOWNLOAD,
message: parsed.message,
code: parsed.code,
details: parsed.details,
};
}
// 如果是API错误响应格式
if (error?.error || error?.message) {
const errorMessage = error.error || error.message || String(error);
const errorCode = error.code;
// 根据错误代码或消息推断错误类型
if (errorCode === 'UNAUTHORIZED' || errorMessage.includes('未登录') || errorMessage.includes('请先登录')) {
return {
type: ErrorType.PERMISSION,
message: '请先登录',
code: errorCode,
details: error.details,
};
}
if (errorCode === 'FORBIDDEN' || errorCode === 'NO_PERMISSION' || errorMessage.includes('权限') || errorMessage.includes('无权限')) {
return {
type: ErrorType.PERMISSION,
message: errorMessage.includes('下载') ? '无权限下载该素材' : '无权限执行此操作',
code: errorCode,
details: error.details,
};
}
if (errorMessage.includes('上传') || errorMessage.includes('upload')) {
return {
type: ErrorType.UPLOAD,
message: errorMessage,
code: errorCode,
details: error.details,
};
}
if (errorMessage.includes('网络') || errorMessage.includes('network') || errorMessage.includes('连接')) {
return {
type: ErrorType.NETWORK,
message: '网络连接失败,请检查网络后重试',
code: errorCode,
details: error.details,
};
}
if (errorMessage.includes('验证') || errorMessage.includes('validation') || errorMessage.includes('格式')) {
return {
type: ErrorType.VALIDATION,
message: errorMessage,
code: errorCode,
details: error.details,
};
}
// 默认返回原始错误消息
return {
type: ErrorType.UNKNOWN,
message: errorMessage,
code: errorCode,
details: error.details,
};
}
// 如果是Error对象
if (error instanceof Error) {
const message = error.message || '操作失败,请稍后重试';
// 根据错误消息推断类型
if (message.includes('权限') || message.includes('无权限')) {
return { type: ErrorType.PERMISSION, message };
}
if (message.includes('网络') || message.includes('network') || message.includes('连接')) {
return { type: ErrorType.NETWORK, message: '网络连接失败,请检查网络后重试' };
}
if (message.includes('上传') || message.includes('upload')) {
return { type: ErrorType.UPLOAD, message };
}
return { type: ErrorType.UNKNOWN, message };
}
// 如果是字符串
if (typeof error === 'string') {
return {
type: ErrorType.UNKNOWN,
message: error || '操作失败,请稍后重试',
};
}
// 默认未知错误
return {
type: ErrorType.UNKNOWN,
message: '操作失败,请稍后重试',
};
}
/**
* 从fetch响应中解析错误
*/
export async function parseFetchError(response: Response): Promise<{
type: ErrorType;
message: string;
code?: string;
details?: string;
}> {
try {
const errorData = await response.json();
return parseApiError(errorData);
} catch {
// 如果无法解析JSON,根据状态码返回错误
if (response.status === 401) {
return { type: ErrorType.PERMISSION, message: '请先登录' };
}
if (response.status === 403) {
return { type: ErrorType.PERMISSION, message: '无权限执行此操作' };
}
if (response.status === 404) {
return { type: ErrorType.UNKNOWN, message: '资源不存在' };
}
if (response.status >= 500) {
return { type: ErrorType.SERVER, message: '服务器错误,请稍后重试' };
}
return { type: ErrorType.UNKNOWN, message: `请求失败 (${response.status})` };
}
}
/**
* 处理错误并显示提示(需要传入showToast函数)
*/
export function handleError(
error: any,
showToast?: (message: string, options?: { variant?: 'success' | 'error' }) => void
): {
type: ErrorType;
message: string;
code?: string;
details?: string;
} {
const parsed = parseApiError(error);
// 如果提供了showToast,自动显示错误
if (showToast) {
showToast(parsed.message, { variant: 'error' });
}
return parsed;
}