mcpField
E
error-responses

error-responses

github.com/yanko-belov开发1336 次安装40 周前更新
代码仓库

关于 error-responses

用于 API 错误处理的编码技能,指导开发者避免向客户端暴露内部信息,并返回一致的结构化错误。

主要功能

  1. 01结构化错误响应
  2. 02机器可读错误码
  3. 03HTTP 状态码指引
  4. 04通过请求 ID 查询日志

适用场景

  1. 01实现 API 错误处理
  2. 02检查控制器异常响应
  3. 03替换返回给客户端的原始错误

安装

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

$npx skills add https://github.com/yanko-belov/code-craft --skill error-responses

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

详细介绍

错误响应

概述

绝不暴露内部错误。返回结构化、安全的错误响应。

原始错误消息会泄露实现细节、助长攻击者的行动,并让用户困惑。错误响应应安全、一致且可操作。

适用场景

  • 在 API 中实现错误处理
  • 向客户端返回错误响应
  • 在控制器中捕获异常
  • 有人要求“直接返回错误消息”

铁律

NEVER expose raw error messages or stack traces to clients.

没有例外:

  • 不能因为“有助于调试”
  • 不能因为“仅供内部 API 使用”
  • 不能因为“我们处于开发环境”
  • 不能因为“前端需要详细信息”

检测:泄露迹象

如果错误暴露了内部信息,立即停止:

// ❌ VIOLATION: Exposing internals
app.get('/users/:id', async (req, res) => {
  try {
    const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
    res.json(user);
  } catch (error) {
    res.status(500).json({ message: error.message });  // Leaks!
  }
});

可能泄露的信息:

  • "relation \"users\" does not exist" - 数据库架构
  • "connect ECONNREFUSED 10.0.1.5:5432" - 内部 IP 地址
  • 包含文件路径的堆栈跟踪
  • 包含表名的 SQL 查询

正确模式:安全的错误响应

// ✅ CORRECT: Structured, safe errors

// Custom error classes
class AppError extends Error {
  constructor(
    public statusCode: number,
    public code: string,
    message: string
  ) {
    super(message);
  }
}

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

class ValidationError extends AppError {
  constructor(public details: Record<string, string[]>) {
    super(400, 'VALIDATION_ERROR', 'Validation failed');
  }
}

// Error handler middleware
app.use((error: Error, req: Request, res: Response, next: NextFunction) => {
  // Log full error internally
  console.error('Error:', {
    message: error.message,
    stack: error.stack,
    path: req.path,
    method: req.method,
  });
  
  // Return safe response
  if (error instanceof ValidationError) {
    return res.status(400).json({
      error: {
        code: error.code,
        message: error.message,
        details: error.details,
      }
    });
  }
  
  if (error instanceof AppError) {
    return res.status(error.statusCode).json({
      error: {
        code: error.code,
        message: error.message,
      }
    });
  }
  
  // Unknown errors - never expose
  res.status(500).json({
    error: {
      code: 'INTERNAL_ERROR',
      message: 'An unexpected error occurred',
    }
  });
});

// Usage in routes
app.get('/users/:id', async (req, res, next) => {
  try {
    const user = await userService.findById(req.params.id);
    if (!user) throw new NotFoundError('User');
    res.json(user);
  } catch (error) {
    next(error);  // Pass to error handler
  }
});

错误响应结构

所有错误使用一致的结构:

interface ErrorResponse {
  error: {
    code: string;        // Machine-readable: 'VALIDATION_ERROR'
    message: string;     // Human-readable: 'Validation failed'
    details?: unknown;   // Additional info (validation errors, etc.)
    requestId?: string;  // For support/debugging
  }
}

// Examples:
// 400 Bad Request
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": {
      "email": ["Invalid email format"],
      "age": ["Must be at least 18"]
    }
  }
}

// 404 Not Found
{
  "error": {
    "code": "NOT_FOUND",
    "message": "User not found"
  }
}

// 500 Internal Error
{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "An unexpected error occurred",
    "requestId": "req_abc123"
  }
}

HTTP 状态码

代码使用场景
400请求错误、验证错误
401未通过身份验证
403已通过身份验证,但未获授权
404未找到资源
409冲突(重复项、状态问题)
422无法处理的实体
429请求过于频繁
500服务器错误(隐藏详情!)
502上游服务故障
503服务不可用

抵御施压的准则

1. “有助于调试”

施压说法:“开发人员需要查看完整错误”

**回应:**在服务器端记录完整错误。返回请求 ID 以便关联查询。

操作:{ requestId: "abc123" } - 开发人员可据此查找日志。

2. “仅供内部 API 使用”

施压说法:“只有我们的服务会调用它”

**回应:**内部服务也可能遭到入侵,日志也可能泄露。所有内容都要保护。

**操作:**在所有地方采用相同的安全错误处理方式。

3. “开发模式”

施压说法:“开发环境显示详情,生产环境隐藏”

**回应:**开发环境的代码会进入生产环境。保持良好的习惯很重要。

**操作:**所有环境都采用相同的处理方式。使用日志进行调试。

危险信号——立即停止并重新考虑

  • res.json({ message: error.message })
  • 在响应中包含堆栈跟踪
  • 在错误消息中包含 SQL 查询
  • 暴露内部 IP 地址或路径
  • 各端点使用不同的错误格式

出现以上任何情况,都意味着:实施恰当的错误处理。

快速参考

暴露信息(错误做法)安全做法
数据库错误消息“发生错误”
堆栈跟踪提供用于查找日志的请求 ID
内部路径通用错误代码
SQL 查询“验证失败”
变量转储结构化错误对象

常见托词(均不成立)

借口实际情况
“有助于调试”在服务器端记录,并返回请求 ID。
“内部 API”内部系统也可能遭到入侵。
“开发模式”所有环境都采用相同的处理方式。
“前端需要详细信息”返回安全、结构化的详细信息。
“这样更快”错误处理成本很低,数据泄露却代价高昂。

归根结底

在内部记录所有信息。绝不向外部暴露任何信息。

返回包含机器可读代码和人类可读消息的一致结构化错误。绝不泄露堆栈跟踪、查询或内部详情。使用请求 ID 进行调试。

评论

支持 Markdown