error.ts 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import { Request, Response, NextFunction } from 'express';
  2. import { logger } from '../utils/logger.js';
  3. import { ERROR_CODES, HTTP_STATUS } from '@media-manager/shared';
  4. export class AppError extends Error {
  5. public readonly statusCode: number;
  6. public readonly code: string;
  7. public readonly isOperational: boolean;
  8. constructor(
  9. message: string,
  10. statusCode: number = HTTP_STATUS.INTERNAL_SERVER_ERROR,
  11. code: string = ERROR_CODES.UNKNOWN,
  12. isOperational: boolean = true
  13. ) {
  14. super(message);
  15. this.statusCode = statusCode;
  16. this.code = code;
  17. this.isOperational = isOperational;
  18. Error.captureStackTrace(this, this.constructor);
  19. }
  20. }
  21. export function errorHandler(
  22. err: Error | AppError,
  23. _req: Request,
  24. res: Response,
  25. _next: NextFunction
  26. ): void {
  27. if (err instanceof AppError) {
  28. logger.warn(`AppError: ${err.message}`, { code: err.code, statusCode: err.statusCode });
  29. res.status(err.statusCode).json({
  30. success: false,
  31. error: {
  32. code: err.code,
  33. message: err.message,
  34. },
  35. });
  36. return;
  37. }
  38. // 未知错误
  39. logger.error('Unexpected error:', err);
  40. res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({
  41. success: false,
  42. error: {
  43. code: ERROR_CODES.UNKNOWN,
  44. message: process.env.NODE_ENV === 'production'
  45. ? 'Internal server error'
  46. : err.message,
  47. },
  48. });
  49. }
  50. // 异步处理器包装
  51. export function asyncHandler<T>(
  52. fn: (req: Request, res: Response, next: NextFunction) => Promise<T>
  53. ) {
  54. return (req: Request, res: Response, next: NextFunction) => {
  55. Promise.resolve(fn(req, res, next)).catch(next);
  56. };
  57. }