Spaces:
Sleeping
Sleeping
| /** | |
| * Error Utilities | |
| * 统一错误处理工具 | |
| */ | |
| import type { ErrorResponse } from '../types' | |
| /** | |
| * 应用错误基类 | |
| */ | |
| export class AppError extends Error { | |
| public readonly statusCode: number | |
| public readonly isOperational: boolean | |
| public readonly details?: any | |
| constructor( | |
| message: string, | |
| statusCode: number = 500, | |
| isOperational: boolean = true, | |
| details?: any | |
| ) { | |
| super(message) | |
| this.statusCode = statusCode | |
| this.isOperational = isOperational | |
| this.details = details | |
| // 维护正确的原型链 | |
| Object.setPrototypeOf(this, new.target.prototype) | |
| Error.captureStackTrace(this) | |
| } | |
| /** | |
| * 转换为 API 错误响应 | |
| */ | |
| toJSON(): ErrorResponse { | |
| return { | |
| error: this.message, | |
| details: this.details, | |
| statusCode: this.statusCode | |
| } | |
| } | |
| } | |
| /** | |
| * 验证错误(400) | |
| */ | |
| export class ValidationError extends AppError { | |
| constructor(message: string, details?: any) { | |
| super(message, 400, true, details) | |
| this.name = 'ValidationError' | |
| } | |
| } | |
| /** | |
| * 未找到错误(404) | |
| */ | |
| export class NotFoundError extends AppError { | |
| constructor(message: string = 'Resource not found', details?: any) { | |
| super(message, 404, true, details) | |
| this.name = 'NotFoundError' | |
| } | |
| } | |
| /** | |
| * 认证错误(401) | |
| */ | |
| export class AuthenticationError extends AppError { | |
| constructor(message: string = 'Authentication required', details?: any) { | |
| super(message, 401, true, details) | |
| this.name = 'AuthenticationError' | |
| } | |
| } | |
| /** | |
| * 权限错误(403) | |
| */ | |
| export class ForbiddenError extends AppError { | |
| constructor(message: string = 'Access forbidden', details?: any) { | |
| super(message, 403, true, details) | |
| this.name = 'ForbiddenError' | |
| } | |
| } | |
| /** | |
| * 冲突错误(409) | |
| */ | |
| export class ConflictError extends AppError { | |
| constructor(message: string, details?: any) { | |
| super(message, 409, true, details) | |
| this.name = 'ConflictError' | |
| } | |
| } | |
| /** | |
| * 内部服务器错误(500) | |
| */ | |
| export class InternalError extends AppError { | |
| constructor(message: string = 'Internal server error', details?: any) { | |
| super(message, 500, false, details) | |
| this.name = 'InternalError' | |
| } | |
| } | |
| /** | |
| * 服务不可用错误(503) | |
| */ | |
| export class ServiceUnavailableError extends AppError { | |
| constructor(message: string = 'Service temporarily unavailable', details?: any) { | |
| super(message, 503, true, details) | |
| this.name = 'ServiceUnavailableError' | |
| } | |
| } | |
| /** | |
| * 超时错误(504) | |
| */ | |
| export class TimeoutError extends AppError { | |
| constructor(message: string = 'Request timeout', details?: any) { | |
| super(message, 504, true, details) | |
| this.name = 'TimeoutError' | |
| } | |
| } | |
| /** | |
| * 任务取消错误 499 | |
| */ | |
| export class JobCancelledError extends AppError { | |
| constructor(message: string = 'Job cancelled', details?: any) { | |
| super(message, 499, true, details) | |
| this.name = 'JobCancelledError' | |
| } | |
| } | |
| /** | |
| * 判断是否为应用错误 | |
| */ | |
| export function isAppError(error: any): error is AppError { | |
| return error instanceof AppError | |
| } | |
| /** | |
| * 判断是否为操作性错误(可恢复) | |
| */ | |
| export function isOperationalError(error: any): boolean { | |
| if (isAppError(error)) { | |
| return error.isOperational | |
| } | |
| return false | |
| } | |
| /** | |
| * 格式化错误信息 | |
| */ | |
| export function formatError(error: any): ErrorResponse { | |
| if (isAppError(error)) { | |
| return error.toJSON() | |
| } | |
| // 处理 Zod 验证错误 | |
| if (error.name === 'ZodError') { | |
| return { | |
| error: 'Validation failed', | |
| details: error.errors, | |
| statusCode: 400 | |
| } | |
| } | |
| // 默认错误 | |
| return { | |
| error: error.message || 'Internal server error', | |
| statusCode: 500 | |
| } | |
| } | |
| /** | |
| * 从错误中提取状态码 | |
| */ | |
| export function getStatusCode(error: any): number { | |
| if (isAppError(error)) { | |
| return error.statusCode | |
| } | |
| if (error.name === 'ZodError') { | |
| return 400 | |
| } | |
| return 500 | |
| } |