2026-08-21 16:00:12.682512+08 / restful-api

HTTP Status Codes and Errors

介绍 RESTful API 中 HTTP 状态码、客户端错误、服务端错误、批量响应和 Problem JSON 的设计规范。

Restful ApiApi DesignOpenapi

HTTP Status Codes and Errors

HTTP 状态码是 REST API 设计的重要组成部分。它们用于表达请求结果,让 API 消费者能够正确处理成功响应、客户端错误和服务端错误。

API 应始终使用标准 HTTP 语义,避免暴露与具体实现相关的细节。


定义成功响应和错误响应

API Specification 必须定义成功响应和服务专属的错误响应。

成功响应和错误响应都是 API 契约的一部分。它们说明客户端应如何调用 API,以及如何处理异常情况。

不过,API 不应记录每一种可能的技术错误,尤其是由服务无法控制的基础设施组件引起的错误。

API 应重点记录:

  • 与业务相关的错误
  • 客户端可以采取不同处理方式的错误
  • 需要在 HTTP 状态码之外补充解释的错误

错误响应可以使用 RFC 7807 的 Problem Details 格式,并通过 application/problem+json 返回详细信息。


使用标准 HTTP 状态码

API 必须按照标准语义使用 HTTP 状态码,不得创建自定义 HTTP 状态码。

使用标准状态码可以提升互操作性,避免 API 消费者产生歧义。

成功状态码

状态码 描述 典型用途
200 OK 标准成功响应。 所有方法
201 Created 资源创建成功。响应可以包含新资源,也可以为空;应通过 Location Header 指明新资源。 POST、PUT
202 Accepted 请求已接受,将进行异步处理。 POST、PUT、PATCH、DELETE
204 No Content 请求成功,但没有响应体。 PUT、PATCH、DELETE
206 Partial Content 基于范围请求返回部分响应。 GET
207 Multi-Status 返回多个操作结果,通常用于批量请求。 POST

重定向状态码

状态码 描述 典型用途
301 Moved Permanently 资源已永久移动到其他 URI。 所有方法
303 See Other 应通过 GET 从其他 URI 获取响应。 POST、PUT、PATCH、DELETE
304 Not Modified 自请求 Header 指定的版本以来,资源没有变化。 GET、HEAD

客户端错误状态码

客户端错误表示请求因为输入无效、身份认证、权限控制或请求冲突而无法完成。

状态码 描述 典型用途
400 Bad Request 通用客户端错误或请求数据无效,也用于载荷校验失败。 所有方法
401 Unauthorized 需要身份认证,或身份认证失败。 所有方法
403 Forbidden 客户端已认证,但没有访问权限。 所有方法
404 Not Found 请求的资源不存在。 所有方法
405 Method Not Allowed 该资源不支持请求使用的 HTTP 方法。 所有方法
406 Not Acceptable 无法根据 Accept Header 生成请求的表示形式。 所有方法
408 Request Timeout 服务端等待请求处理时超时。 所有方法
409 Conflict 请求与当前资源状态冲突,例如重复创建或并发更新冲突。 POST、PUT、PATCH、DELETE
410 Gone 资源过去存在,但已经被永久移除。 所有方法
412 Precondition Failed 条件请求失败,例如使用 If-Match 进行乐观锁控制时失败。 PUT、PATCH、DELETE
415 Unsupported Media Type 请求体格式不受支持,或缺少必要的 Content-Type。 POST、PUT、PATCH、DELETE
423 Locked 资源暂时被锁定,例如正在处理中。 PUT、PATCH、DELETE
428 Precondition Required 服务端要求使用条件请求,以防止更新丢失。 所有方法
429 Too Many Requests 客户端超过速率限制。 所有方法

服务端错误状态码

服务端错误表示服务在处理一个有效请求时发生了失败。

状态码 描述 典型用途
500 Internal Server Error 未预期的服务端执行错误。根据具体情况,客户端可以考虑重试。 所有方法
501 Not Implemented 服务端不支持请求的功能。 所有方法
503 Service Unavailable 服务暂时不可用,例如依赖服务不可用。条件允许时应使用 Retry-After Header。 所有方法

使用最具体的 HTTP 状态码

API 应始终返回能够准确描述请求结果的最具体 HTTP 状态码。

如果存在更具体的状态码,应避免使用笼统的 400 或 500。

例如,用户已经存在时,创建用户请求应返回:

http
HTTP/1.1 409 Conflict

而不是返回笼统的 400 Bad Request。


批量请求和批处理响应

批量操作可能包含多个相互独立的操作。由于单个 HTTP 响应码无法表达多个结果,当各个操作产生不同结果时,应使用:

text
207 Multi-Status

规则:

  • 如果需要报告每个独立操作的结果,批量请求应返回 207。
  • 响应体必须包含每个独立操作的状态信息。
  • 只有当请求在独立处理开始前就失败,或发生意外的全局失败时,才应返回 4xx 或 5xx。

示例:

json
{
  "results": [
    {
      "id": "123",
      "status": 200
    },
    {
      "id": "456",
      "status": 404,
      "detail": "Resource not found"
    }
  ]
}

使用 Problem JSON 对象

API 应使用 RFC 7807 Problem Details 格式返回错误响应。

媒体类型:

text
application/problem+json

Problem 响应提供 HTTP 状态码之外的额外信息,通常包含问题类型、标题、状态、详细说明和具体发生位置。

示例响应:

http
HTTP/1.1 503 Service Unavailable
Content-Type: application/problem+json
json
{
  "type": "/problems/service-unavailable",
  "title": "Service unavailable",
  "status": 503,
  "detail": "The dependent service is temporarily unavailable.",
  "instance": "/requests/abc123"
}

不要暴露堆栈信息

API 绝不能在响应中暴露堆栈信息。

堆栈信息可能:

  • 泄露内部实现细节
  • 暴露敏感信息
  • 造成安全风险
  • 诱使客户端依赖具体实现行为

应返回以下内容:

  • 标准 HTTP 状态码
  • Problem JSON 对象
  • 对客户端安全的错误描述

避免:

json
{
  "error": "NullReferenceException",
  "stackTrace": "at Service.UserHandler.Process()..."
}

推荐:

json
{
  "type": "/problems/internal-error",
  "title": "Internal server error",
  "status": 500,
  "detail": "An unexpected error occurred."
}

总结

良好的 REST API 应:

  • 在 API Specification 中定义成功响应和错误响应。
  • 只使用标准 HTTP 状态码。
  • 选择可用的最具体状态码。
  • 对需要报告独立结果的批量操作使用 207 Multi-Status。
  • 使用 application/problem+json 返回详细错误信息。
  • 绝不暴露堆栈信息或内部实现细节。