一个标准化的HTTP响应错误格式

221 阅读4分钟

一个标准化的HTTP响应错误格式

HTTP使用状态码来表示服务器试图满足请求的结果。在服务器无法处理请求的情况下,我们可以从各种HTTP错误代码中进行选择。

不幸的是,仅仅是状态代码往往不能为API客户提供足够的信息。例如,服务器可能会以状态代码400(Bad Request)来回应,表示客户端发送了一个无效的请求。如果响应体能告诉我们请求的哪一部分无效或如何解决这个问题,那不是很好吗?

状态代码用于定义更高层次的错误类别,而错误细节通常是响应体的一部分。许多API使用自定义错误格式的响应体来提供额外的问题信息。然而,这里也有一个标准可以帮助我们,在RFC 2707中定义。

RFC 7807为JSON和XML中的问题细节定义了一个数据模型。在为你的API提出一个新的通用故障错误响应格式之前,也许值得研究一下RFC 7807。然而,如果使用你自己的特定领域的格式更适合你的应用,那也是完全可以的。

RFC 7807:HTTP API的问题细节

一个使用RFC 7807的HTTP响应可能看起来像这样:

HTTP/1.1 400 Bad request
Content-Type: application/problem+json
Content-Language: en

{
    "type": "https://api.my-cool-example.com/problems/required-field-missing",
    "title": "Required field is missing",
    "detail": "Article with id 1234 cannot be updated because the required field 'title' is missing",
    "status": 400,
    "instance": "/articles/1234",
    "field": "title"
}

像往常一样,HTTP状态代码(400,坏请求)给了我们一个问题的大致指示。注意响应的Content-Type是application/problem+json。这告诉我们响应包含一个符合RFC 7807标准的主体。当使用XML而不是JSON时,会使用Content-Typeapplication/problem+xml

一个问题细节的JSON响应可以有以下成员:

  • type (string) - 一个识别问题类型的URI参考。
  • title (string) - 问题类型的简短的人可读摘要。它不应该在同一问题类型的多次出现之间发生变化,除非是为了本地化的目的。
  • status (数字) - 由源服务器生成的HTTP状态代码。
  • detail (string) - 关于这个特定问题发生的可读描述。
  • instance (string) - 一个识别与这个具体问题发生相关的资源的URI。

所有的字段都是可选的。然而,你至少应该提供一个类型值,因为消费者会用它来识别具体的问题类型。消费者不应该解析标题细节字段。

问题类型

问题类型是用来识别特定的问题。一个问题类型必须记录:

  • 一个类型URI(在响应的类型 字段中使用)。
  • 一个描述问题的标题(在响应的标题字段中使用)。
  • 它所使用的HTTP状态代码。

类型URI应该解析为该问题的人类可读文档(例如,HTML文档)。这个URI应该在你的控制之下,并且随着时间的推移而稳定。

如果合适的话,问题类型也可以指定使用Retry-After响应头。

RFC 7807保留了一个特殊的URI作为问题类型:about:blank。如果问题除了HTTP状态码之外没有额外的语义,就可以使用问题类型about:blank。在这种情况下,标题应该与该代码的HTTP状态短语相同(例如,HTTP状态400的坏请求)。

扩展成员

问题类型可以用额外的成员扩展问题细节对象,以提供额外的信息。

上面显示的示例响应中的字段 成员是这种扩展成员的一个例子。它属于required-field-missing问题类型,并指出缺少的字段。消费者可以解析这个成员,为终端用户构建一个适当的错误信息。

结论

单纯的HTTP状态码往往不足以提供有意义的问题描述。

RFC 7807定义了一个标准化的格式,用于在HTTP响应正文中提供更详细的问题描述。在想出另一种自定义的错误响应格式之前,看看RFC 7807的问题格式可能是一个好主意。