mcpField
E
error-handling

error-handling

github.com/pluginagentmarketplace开发260 次安装43 周前更新
代码仓库

关于 error-handling

面向 Node.js 开发者的错误处理学习技能,涵盖从自定义异常到 Express 中间件及进程级故障的处理。内容还包括重试逻辑、响应格式、测试和故障排查。

主要功能

  1. 01自定义类型化错误类
  2. 02同步与异步错误处理
  3. 03Express 错误中间件
  4. 04进程级错误处理器
  5. 05指数退避重试
  6. 06测试与故障排查指南

适用场景

  1. 01构建健壮的 Node.js 应用
  2. 02集中处理 Express API 错误
  3. 03处理数据库或外部 API 调用失败
  4. 04测试错误行为与恢复逻辑

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pluginagentmarketplace/custom-plugin-nodejs --skill error-handling

安装后在 Claude Code 中输入/error-handling确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
config.yaml
schema.json
references/
GUIDE.md
PATTERNS.md
scripts/
validate.py

详细介绍

Node.js 错误处理技能

掌握错误处理模式,构建能够优雅地处理失败并提供有意义反馈的弹性 Node.js 应用程序。

快速入门

错误处理分为 4 层:

  1. 自定义错误类 - 类型明确、信息丰富的错误
  2. Try/Catch 模式 - 同步和异步处理
  3. Express 中间件 - 集中处理 API 错误
  4. 进程处理器 - 捕获未处理的异常

核心概念

自定义错误类
// Base application error
class AppError extends Error {
  constructor(message, statusCode, code) {
    super(message);
    this.statusCode = statusCode;
    this.code = code;
    this.isOperational = true;
    Error.captureStackTrace(this, this.constructor);
  }
}

// Specific error types
class ValidationError extends AppError {
  constructor(message, details = []) {
    super(message, 400, 'VALIDATION_ERROR');
    this.details = details;
  }
}

class NotFoundError extends AppError {
  constructor(resource = 'Resource') {
    super(`${resource} not found`, 404, 'NOT_FOUND');
  }
}

class UnauthorizedError extends AppError {
  constructor(message = 'Authentication required') {
    super(message, 401, 'UNAUTHORIZED');
  }
}

class ForbiddenError extends AppError {
  constructor(message = 'Access denied') {
    super(message, 403, 'FORBIDDEN');
  }
}
异步错误处理
// Async wrapper for Express routes
const asyncHandler = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

// Usage
router.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await User.findById(req.params.id);
  if (!user) throw new NotFoundError('User');
  res.json(user);
}));
Express 错误中间件
const errorHandler = (err, req, res, next) => {
  // Log error
  logger.error({
    message: err.message,
    stack: err.stack,
    code: err.code,
    url: req.originalUrl
  });

  // Handle operational errors
  if (err.isOperational) {
    return res.status(err.statusCode).json({
      success: false,
      error: {
        message: err.message,
        code: err.code,
        ...(err.details && { details: err.details })
      }
    });
  }

  // Production: hide internal errors
  if (process.env.NODE_ENV === 'production') {
    return res.status(500).json({
      success: false,
      error: { message: 'Internal server error', code: 'INTERNAL_ERROR' }
    });
  }

  // Development: show stack
  res.status(500).json({
    success: false,
    error: { message: err.message, stack: err.stack }
  });
};

学习路径

初级(1-2 周)
  • ✅ 理解 Error 类型
  • ✅ 使用 try/catch 处理同步代码
  • ✅ 使用 Promise .catch() 处理错误
  • ✅ 基础 Express 错误中间件
中级(3-4 周)
  • ✅ 自定义错误类
  • ✅ 异步错误包装器
  • ✅ 集中式错误处理
  • ✅ 使用 Winston 记录错误日志
高级(5-6 周)
  • ✅ 生产环境错误监控
  • ✅ 优雅关闭
  • ✅ 断路器模式
  • ✅ 错误恢复策略

进程级错误处理

// Uncaught exceptions
process.on('uncaughtException', (error) => {
  console.error('Uncaught Exception:', error);
  logger.fatal({ error }, 'Uncaught exception');
  process.exit(1);
});

// Unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection:', reason);
  logger.error({ reason }, 'Unhandled rejection');
});

// Graceful shutdown
process.on('SIGTERM', async () => {
  console.log('SIGTERM received. Graceful shutdown...');
  server.close(() => console.log('HTTP server closed'));
  await mongoose.connection.close();
  process.exit(0);
});

使用指数退避重试

async function retryOperation(fn, options = {}) {
  const { maxRetries = 3, delay = 1000, backoff = 2 } = options;
  let lastError;

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;
      if (attempt === maxRetries) throw error;

      const waitTime = delay * Math.pow(backoff, attempt - 1);
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }
  }
  throw lastError;
}

错误响应格式

// Success
{ "success": true, "data": { ... } }

// Error
{
  "success": false,
  "error": {
    "message": "User not found",
    "code": "NOT_FOUND",
    "details": [],
    "timestamp": "2024-01-15T10:30:00.000Z"
  }
}

单元测试模板

describe('Error Handling', () => {
  describe('ValidationError', () => {
    it('should create error with correct properties', () => {
      const error = new ValidationError('Invalid input', [
        { field: 'email', message: 'Required' }
      ]);

      expect(error.statusCode).toBe(400);
      expect(error.code).toBe('VALIDATION_ERROR');
      expect(error.isOperational).toBe(true);
    });
  });

  describe('asyncHandler', () => {
    it('should catch async errors', async () => {
      const mockNext = jest.fn();
      const handler = asyncHandler(async () => {
        throw new Error('Test error');
      });

      await handler({}, {}, mockNext);
      expect(mockNext).toHaveBeenCalledWith(expect.any(Error));
    });
  });
});

故障排除

问题原因解决方案
未处理的拒绝警告缺少 .catch()添加进程处理器和本地捕获处理
错误被悄然吞掉空的 catch 块记录或重新抛出错误
缺少堆栈跟踪未调用 Error.captureStackTrace使用 AppError 基类
错误导致内存泄漏存储错误引用使用 WeakMap 或进行清理

适用场景

在以下情况下使用恰当的错误处理:

  • 构建生产环境 Node.js 应用程序
  • 使用 Express 创建 REST API
  • 处理数据库操作
  • 处理外部 API 调用
  • 实现重试逻辑

相关技能

  • Express REST API(API 错误响应)
  • 异步编程(Promise 拒绝)
  • 测试与调试(错误测试)

资源

评论

支持 Markdown