447

我正在尝试使用我正在研究的“类似 REST”的 API 找出在不同场景下返回的正确状态代码。假设我有一个端点,允许以 JSON 格式发布购买。它看起来像这样:

{
    "account_number": 45645511,
    "upc": "00490000486",
    "price": 1.00,
    "tax": 0.08
}

如果客户向我发送“sales_tax”(而不是预期的“tax”),我应该返回什么。目前,我正在返回 400。但是,我已经开始质疑自己。我真的应该退回 422 吗?我的意思是,它是 JSON(受支持)并且它是有效的 JSON,它只是不包含所有必需的字段。

4

8 回答 8

521

400 Bad Request现在似乎是您的用例的最佳 HTTP/1.1 状态代码。

在您提出问题(以及我最初的回答)时,RFC 7231还不是一回事。在这一点上我反对,400 Bad Request因为RFC 2616说(强调我的):

由于语法错误,服务器无法理解该请求。

并且您描述的请求是语法有效的 JSON 封装在语法有效的 HTTP 中,因此服务器对请求的语法没有问题。

然而 ,正如 Lee Saferite 在评论中指出的那样,已淘汰 RFC 2616 的 RFC 7231 不包括该限制

400 (Bad Request) 状态码表示服务器不能或不会处理请求,因为某些东西被认为是客户端错误(例如,格式错误的请求语法、无效的请求消息帧或欺骗性请求路由)。


但是,在重新措辞之前(或者如果您想对 RFC 7231 现在只是一个提议的标准提出质疑),对于您的用例来说,这422 Unprocessable Entity似乎不是一个不正确的HTTP 状态代码,因为正如RFC 4918 的介绍所说:

虽然 HTTP/1.1 提供的状态码足以描述 WebDAV 方法遇到的大多数错误情况,但有些错误并没有完全归入现有类别。本规范定义了为 WebDAV 方法开发的额外状态代码(第 11 节)

并且描述422说:

422(Unprocessable Entity)状态码意味着服务器理解请求实体的内容类型(因此 415(Unsupported Media Type)状态码是不合适的),并且请求实体的语法是正确的(因此是 400(Bad Request) ) 状态码不合适)但无法处理包含的指令。

(注意对语法的引用;我怀疑 7231 也部分过时了 4918)

这听起来与您的情况完全一样,但以防万一有任何疑问,它会继续说:

例如,如果 XML 请求正文包含格式正确(即语法正确)但语义错误的 XML 指令,则可能会出现这种错误情况。

(将“XML”替换为“JSON”,我认为我们可以同意这是您的情况)

现在,有些人会反对 RFC 4918 是关于“Web 分布式创作和版本控制 (WebDAV) 的 HTTP 扩展”,并且您(大概)没有做任何涉及 WebDAV 的事情,因此不应该使用它。

考虑到在原始标准中使用明确不涵盖这种情况的错误代码和从准确描述情况的扩展中使用错误代码之间的选择,我会选择后者。

此外,RFC 4918 第 21.4 节引用了IANA 超文本传输​​协议 (HTTP) 状态代码注册表,其中 422 可以找到。

我建议 HTTP 客户端或服务器使用该注册表中的任何状态代码是完全合理的,只要它们正确使用即可。


但是从 HTTP/1.1 开始,RFC 7231 具有吸引力,所以只需使用400 Bad Request!

于 2013-11-26T11:26:25.433 回答
100

案例研究:GitHub API

https://developer.github.com/v3/#client-errors

也许从众所周知的 API 复制是一个明智的想法:

接收请求正文的 API 调用存在三种可能的客户端错误类型:

发送无效的 JSON 将导致 400 Bad Request 响应。

HTTP/1.1 400 Bad Request
Content-Length: 35

{"message":"Problems parsing JSON"}

发送错误类型的 JSON 值将导致 400 Bad Request 响应。

HTTP/1.1 400 Bad Request
Content-Length: 40

{"message":"Body should be a JSON object"}

发送无效字段将导致 422 Unprocessable Entity 响应。

HTTP/1.1 422 Unprocessable Entity
Content-Length: 149

{
  "message": "Validation Failed",
  "errors": [
    {
      "resource": "Issue",
      "field": "title",
      "code": "missing_field"
    }
  ]
}
于 2018-09-17T08:46:05.770 回答
41

400 Bad Request是适合您的用例的 HTTP 状态代码。该代码由 HTTP/0.9-1.1 RFC 定义。

由于语法错误,服务器无法理解该请求。客户端不应该在没有修改的情况下重复请求。

https://www.rfc-editor.org/rfc/rfc2616#section-10.4.1

422 Unprocessable Entity由 RFC 4918 - WebDav 定义。请注意,与 400 相比略有不同,请参阅下面的引用文本。

如果 XML 请求正文包含格式正确(即语法正确)但语义错误的 XML 指令,则可能会发生这种错误情况。

为了保持统一的界面,您应该仅在 XML 响应的情况下使用 422,并且您还应该支持 Webdav 扩展定义的所有状态代码,而不仅仅是 422。

https://www.rfc-editor.org/rfc/rfc4918#page-78

另请参阅 Mark Nottingham 关于状态码的帖子:

尝试将应用程序的每个部分“深度”映射到 HTTP 状态代码是错误的;在大多数情况下,您要瞄准的粒度级别要粗得多。如有疑问,可以在没有更合适的情况下使用通用状态代码 200 OK、400 Bad Request 和 500 Internal Service Error

如何考虑 HTTP 状态码

于 2013-04-23T14:32:53.437 回答
40

为了反映截至 2015 年的状态:

从行为上讲,400 和 422 响应代码都将被客户和中介视为相同,因此它实际上不会对您使用的具体差异产生影响。

但是,我希望看到 400 当前使用得更广泛,此外,HTTPbis 规范提供的说明使其更适合两种状态代码:

  • HTTPbis 规范阐明了 400 的意图不仅仅是为了语法错误。现在使用更广泛的短语“表明服务器不能或不会处理请求,因为某些东西被认为是客户端错误”。
  • 422 专门是 WebDAV 扩展,在 RFC 2616 或较新的HTTPbis 规范中未引用。

就上下文而言,HTTPbis 是 HTTP/1.1 规范的修订版,它试图澄清不清楚或不一致的领域。一旦达到批准状态,它将取代 RFC2616。

于 2015-01-13T10:16:23.593 回答
21

没有正确答案,因为它取决于您的请求对“语法”的定义。最重要的是你:

  1. 始终如一地使用响应代码
  2. 在响应正文中包含尽可能多的附加信息,以帮助使用您的 API 的开发人员弄清楚发生了什么。=

在每个人都因为我说这里没有正确或错误的答案而跳起来之前,让我解释一下我是如何得出这个结论的。

在此特定示例中,OP 的问题是关于包含与预期不同的密钥的 JSON 请求。现在,从自然语言的角度来看,接收到的密钥名称与预期的密钥非常相似,但严格来说,它是不同的,因此(通常)不被机器识别为等效的。

正如我上面所说,决定因素是语法的含义。如果请求是使用 Content Type 发送的application/json,那么是的,请求在语法上是有效的,因为它是有效的 JSON 语法,但在语义上无效,因为它与预期的不匹配。(假设对什么使所讨论的请求在语义上有效或无效有一个严格的定义)。

另一方面,如果请求是使用更具体的自定义内容类型发送的application/vnd.mycorp.mydatatype+json,也许,确切地指定了预期的字段,那么我会说请求很容易在语法上无效,因此 400 响应。

在有问题的情况下,由于key是错误的,而不是value如果有关于什么是有效键的规范,则会出现语法错误。如果没有对有效键的规范,或者错误与 value 相关,那么这将是一个语义错误。

于 2014-01-31T19:17:47.923 回答
4

422 不可处理实体解释更新:2017 年 3 月 6 日

什么是 422 不可处理实体?

当请求格式正确时会出现 422 状态代码,但是由于语义错误而无法处理。此 HTTP 状态是在 RFC 4918 中引入的,更具体地适用于 Web 分布式创作和版本控制 (WebDAV) 的 HTTP 扩展。

关于开发人员是否应该向客户端返回 400 与 422 错误存在一些争议(更多关于以下两种状态之间的差异)。但是,在大多数情况下,只有在支持 WebDAV 功能时才应返回 422 状态。

从 RFC 4918 的第 11.2 节中提取的 422 状态代码的逐字定义可以在下面阅读。

422(Unprocessable Entity)状态码意味着服务器理解请求实体的内容类型(因此 415(Unsupported Media Type)状态码是不合适的),并且请求实体的语法是正确的(因此是 400(Bad Request) ) 状态码不合适)但无法处理包含的指令。

定义接着说:

例如,如果 XML 请求正文包含格式正确(即语法正确)但语义错误的 XML 指令,则可能会出现这种错误情况。

400 与 422 状态码

错误请求错误使用 400 状态代码,如果请求语法格式错误、包含无效的请求消息帧或具有欺骗性的请求路由,则应将其返回给客户端。此状态代码可能看起来与 422 不可处理实体状态非常相似,但是,区分它们的一小部分信息是请求实体的 422 错误的语法是正确的,而生成 400 的请求的语法错误是不正确的。

422 状态的使用应仅用于非常特殊的用例。在大多数其他由于语法格式错误而发生客户端错误的情况下,应使用 400 Bad Request 状态。

https://www.keycdn.com/support/422-unprocessable-entity/

于 2017-07-13T05:06:56.280 回答
2

您的案例: HTTP 400从 REST 角度来看,您的案例是正确的状态代码,因为它在语法上不正确,无法发送sales_tax而不是tax,尽管它是有效的 JSON。在将 JSON 映射到对象时,大多数服务器端框架通常都会强制执行此操作。但是,有些 REST 实现忽略key了 JSON 对象中的 new。在这种情况下,content-type服务器端可以强制执行只接受有效字段的自定义规范。

422的理想场景:

在理想情况下,如果服务器理解请求实体的内容类型并且请求实体的语法正确但由于其语义错误而无法处理数据,则首选422作为响应发送并且通常可以接受。

400 超过 422 的情况:

请记住,响应代码 422 是扩展的 HTTP (WebDAV) 状态代码。仍然有一些 HTTP 客户端/前端库不准备处理 422。对他们来说,它就像“HTTP 422 错误,因为它不是 HTTP”一样简单。从服务的角度来看,400 并不是很具体。

在企业架构中,服务主要部署在 SOA、IDM 等服务层上。它们通常为多个客户端提供服务,从非常旧的本地客户端到最新的 HTTP 客户端。如果其中一个客户端不处理 HTTP 422,则选项是要求客户端升级或将您的响应代码更改为每个人的 HTTP 400。以我的经验,这在当今非常罕见,但仍有可能。因此,在决定 HTTP 响应代码之前,始终需要仔细研究您的架构。

为了处理这样的情况,服务层通常使用versioning或设置configuration标志来让严格的 HTTP 一致性客户端发送 400,并为其余的客户端发送 422。这样,它们为现有消费者提供向后兼容性支持,同时为新客户端提供使用 HTTP 422 的能力。


RFC7321的最新更新说:

The 400 (Bad Request) status code indicates that the server cannot or
   will not process the request due to something that is perceived to be
   a client error (e.g., malformed request syntax, invalid request
   message framing, or deceptive request routing).

这确认服务器可以为无效请求发送 HTTP 400。400 不再只是指语法错误,但是,只要客户端可以处理,422 仍然是真正的响应。

于 2017-02-22T18:21:35.677 回答
0

首先,这是一个非常好的问题。

400 Bad Request - 当请求中缺少关键信息时

例如,授权标头或内容类型标头。服务器绝对需要它来理解请求。这可能因服务器而异。

422 Unprocessable Entity - 无法解析请求正文时。

这没有 400 严重。请求已到达服务器。服务器已确认请求具有正确的基本结构。但是请求正文中的信息无法解析或理解。

例如Content-Type: application/xml,当请求正文是 JSON 时。

这是一篇列出状态代码及其在 REST API 中的使用的文章。 https://metamug.com/article/status-codes-for-rest-api.php

于 2017-11-09T14:20:52.787 回答