4、同步API中的校验失败响应设计:HTTP状态码选择(400 Bad Request)、错误响应体结构(code、message、details)

在异步导出流程中,同步API(即发起导出请求的端点)承担着第一道防线的作用。当客户端提交的参数不符合规范时,API必须立即、明确地拒绝请求,而不是将错误参数传递到异步队列中。本节将详细阐述同步校验失败时的响应设计标准,包括HTTP状态码的选择与错误响应体的结构化设计。

4.1 HTTP状态码选择:400 Bad Request

对于参数校验失败,业界公认且最符合HTTP语义的状态码是 400 Bad Request。该状态码表示服务器因请求语法错误、参数格式无效或参数缺失而无法处理请求。在异步导出场景中,以下情况应统一返回400:

  • 必填参数缺失:如未提供 export_type 或 date_range。
  • 参数格式错误:如日期格式不是 YYYY-MM-DD,或枚举值不在允许范围内。
  • 参数逻辑冲突:如同时指定了 start_date 和 last_days 两个互斥参数。
  • 参数超出业务范围:如请求导出的数据量超过单次上限(例如超过10万行)。
设计原则: 不要使用 422 Unprocessable Entity(语义偏语义校验)或 500 Internal Server Error(表示服务端异常)。400 Bad Request 是参数校验失败的标准答案,客户端和中间件都能正确识别。

4.2 错误响应体结构:code、message、details

仅返回状态码不足以帮助客户端快速定位问题。我们设计一个三层结构的JSON响应体,确保错误信息既简洁又具备可操作性:

字段 类型 必填 说明
code string 是 业务错误码,用于程序化判断,如 PARAM_MISSING、PARAM_INVALID、PARAM_CONFLICT
message string 是 面向开发者的可读错误摘要,如 "必填参数 export_type 缺失"
details array 否 参数级错误详情列表,每个元素包含 field、reason、value(可选)

details 数组中的每个对象结构:

字段 类型 说明
field string 出错的参数名,如 date_range.start
reason string 具体错误原因,如 "日期格式必须为 YYYY-MM-DD"
value any 客户端传入的原始值(可选,用于调试)

4.3 完整响应示例

以下是一个参数校验失败的完整HTTP响应:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "code": "PARAM_INVALID",
  "message": "请求参数校验失败,请检查 details 中的具体错误",
  "details": [
    {
      "field": "date_range.start",
      "reason": "日期格式无效,期望格式为 YYYY-MM-DD",
      "value": "2024/01/01"
    },
    {
      "field": "export_type",
      "reason": "不支持的导出类型,可选值: [csv, xlsx, json]",
      "value": "pdf"
    }
  ]
}
最佳实践: 当只有一个参数错误时,details 数组仍应返回一个元素,保持响应结构的一致性。客户端可以统一遍历 details 数组展示错误,无需区分单错误与多错误场景。

4.4 同步校验流程与响应映射

下图展示了从请求到达、参数校验到错误响应的完整流程:

同步API参数校验流程与错误响应映射 客户端请求 参数校验器 校验通过 → 继续处理 校验失败 构建错误响应体 返回 400 + JSON 错误响应体结构 code: 业务错误码 message: 可读摘要 details: 参数级详情数组

4.5 常见校验场景与code映射

为方便客户端程序化处理,我们预定义一组标准业务错误码:

场景 HTTP状态码 code message 示例
必填参数缺失 400 PARAM_MISSING "必填参数 export_type 缺失"
参数格式错误 400 PARAM_INVALID "参数 date_range.start 格式无效"
参数值超出范围 400 PARAM_OUT_OF_RANGE "导出行数超过上限 100000"
参数逻辑冲突 400 PARAM_CONFLICT "start_date 与 last_days 不能同时指定"
枚举值不支持 400 PARAM_UNSUPPORTED "不支持的导出格式 pdf"
注意: 不要将业务校验错误(如"该用户无导出权限")映射到400。权限相关错误应使用 403 Forbidden,并采用独立的错误码体系。400 只用于请求参数本身的语法或语义错误。

4.6 设计要点总结

  • 状态码统一:所有参数校验失败均使用 400 Bad Request,避免混用 422、406 等非标准状态码。
  • 响应体三层结构:code 用于程序判断,message 用于快速理解,details 用于精确定位。
  • details 数组化:即使只有一个错误也返回数组,保持客户端处理逻辑的一致性。
  • 原始值回传:在 details.value 中回传客户端传入的原始值,便于调试和前端表单回显。
  • 错误码可扩展:业务错误码采用大写蛇形命名,团队可在此基础上扩展自定义错误码。