【问题标题】:400 vs 422 response to POST of data400 vs 422 对 POST 数据的响应
【发布时间】:2013-04-14 13:50:15
【问题描述】:

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

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

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

【问题讨论】:

标签: rest http-status-codes


【解决方案1】:

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

在您提出问题时(以及我最初的回答),RFC 7231 不是一个东西;当时我反对400 Bad Request,因为RFC 2616 说(重点是我的):

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

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

然而as pointed out by Lee Saferite in the commentsRFC 7231, which obsoletes RFC 2616, does not include that restriction

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


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

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

the description of 422 说:

422 (Unprocessable Entity) 状态码表示服务器 理解请求实体的内容类型(因此 415(不支持的媒体类型)状态码不合适),并且 请求实体的语法是正确的(因此是 400 (Bad Request) 状态码不合适)但无法处理包含的 说明。

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

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

例如,如果 XML 请求正文包含格式正确(即语法正确),但是 语义错误的 XML 指令。

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

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

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

此外,RFC 4918 Section 21.4 指的是IANA Hypertext Transfer Protocol (HTTP) Status Code Registry,其中可以找到 422。

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


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

【讨论】:

  • 您的回答 (422) 对我来说很有意义。这也是 Rails (respond_with) 在由于验证错误而无法处理资源时使用的方法。
  • 请注意此处在非 WebDAV 规范中使用 422:tools.ietf.org/html/rfc5789#section-2.2
  • 作为一个更新,RFC 7231 对响应代码 400 的描述有所不同,从而改变了语义。
  • 我很抱歉 - 我更新了这个答案以反映 RFC 的变化并且失去了一些清晰度;我会尝试重构。使用 422 几乎肯定安全,但现在你应该使用 400。
  • 我仍然认为规范可能会更清晰。中给出的示例是客户做错事的明显案例。 OP的情况也属于这一类。但是,有些情况像“我明白你的要求,但我拒绝这样做,因为有一些商业规则反对它”并不是那么明确。这不完全是客户端的错,因此根据相同的规范,实际上可能会应用 403:“但是,由于与凭据无关的原因,可能会禁止请求”。不过,我更愿意为权限相关的东西与“它无法完成”分别提供代码。
【解决方案2】:

案例研究: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"
    }
  ]
}

【讨论】:

  • 我认为这是正确且可以理解的答案。
  • 不能再投票了。希望更多赞成的答案会提到这个。规范(RFC、IANA)明显未能提供明确的定义和两者之间的区别。所以答案归结为最佳实践,GitHub 给了我们一个。
  • 这必须是公认的答案。此外,答案中提供的网址不再起作用,并将您带到主页。最新网址为:docs.github.com/en/rest/overview/….
  • 所以 422 是正确的,例如“价格”或“税”不是有效数字?基本上违反了预期的架构。或者,如果您尝试向不在您系统中的人收费,而您只向注册客户收费?
【解决方案3】:

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 没有更合适的服务时出错

How to Think About HTTP Status Codes

【讨论】:

  • 422 代码是 IANA 注册表iana.org/assignments/http-status-codes/http-status-codes.xhtml 的一部分,因此任何恕我直言都没有任何意义。无论如何,Facebook 和 Twitter REST API 重新发明了自己的代码,并且不使用 RFC/IANA 标准。所以你可以做到。
  • 第 11 节特别声明它们被添加到整个规范中,而不仅仅是在 WebDav 规范中:The following status codes are added to those defined in HTTP/1.1 [RFC2616].
  • 仅仅因为代码被描述为 WebDAV 规范的一部分并不意味着它是特定于 WebDAV 的!状态码应该是通用的。
【解决方案4】:

反映截至 2015 年的状态:

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

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

  • HTTPbis 规范阐明了 400 的意图,它不仅仅针对语法错误。现在使用更广泛的短语“表明服务器由于被认为是客户端错误而无法或不会处理请求”。
  • 422 是专门的 WebDAV 扩展,在 RFC 2616 或更新的 HTTPbis specification 中未引​​用。

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

【讨论】:

  • 那么 403 Forbidden 不是也可以用于这种情况吗? Quote: 403(Forbidden)状态码表示服务器理解请求但拒绝授权...如果请求中提供了身份验证凭据,则服务器认为它们不足以授予访问权限...但是,由于与凭据无关的原因,可能会禁止请求。 因此,看起来 403 可用于拒绝身份验证之外的请求。
  • @garbagecollector 请注意“由于凭据之外的原因而被拒绝”!=“由于身份验证之外的原因而被拒绝。”具体来说,有很多方法可以在不使用凭据的情况下对某人进行身份验证。
  • @garbagecollector 不,凭据表示身份验证(“你是谁”),失败时将是 401。授权(“你能做什么”)在失败时将是 403。此处的完整解释:stackoverflow.com/a/6937030/137948 均不适用于 OP 的“缺失字段”情况,因为无论哪个用户尝试,错误都是相同的。我同意 400 是正确答案。
【解决方案5】:

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

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

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

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

正如我上面所说,决定因素是语法的含义。如果发送的请求的内容类型为 application/json,那么是的,请求是语法有效的,因为它是有效的 JSON 语法,但不是语义有效,因为它没有不符合预期。 (假设严格定义了使所讨论的请求在语义上有效与否的原因)。

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

在有问题的情况下,由于 key 是错误的,而不是 value,因此存在 syntax 错误 如果有是关于什么是有效密钥的规范。 如果没有有效键的规范,或者错误是有值的,那么这将是一个语义错误。

【讨论】:

  • 非常被低估的答案 - 感谢您措辞得当的解释。
  • 正是我对此事的看法!我来自 XML SOAP 背景,架构概念刚刚进入我的血液和 JSON 文档,而不是公布他们的架构。对我来说,服务器是否“理解”请求。如果服务器不知道“sales_tax”是什么,那么它只是 400:“我不知道你发给我什么,但绝对不是我想要的。”。
  • 谢谢,现在知道我应该使用哪一个了。
【解决方案6】:

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

什么是 422 不可处理实体?

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

关于是否开发者存在一些争议 应该向客户端返回 400 vs 422 错误(更多关于差异 在以下两种状态之间)。但是,在大多数情况下,这是同意的 仅当您支持 WebDAV 时,才应返回 422 状态 能力。

422 状态码的逐字定义,取自章节 RFC 4918 中的 11.2 可以在下面阅读。

422 (Unprocessable Entity) 状态码表示服务器 理解请求实体的内容类型(因此 415(不支持的媒体类型)状态码不合适),并且 请求实体的语法是正确的(因此是 400 (Bad Request) 状态码不合适)但无法处理包含的 说明。

定义接着说:

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

400 与 422 状态码

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

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

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

【讨论】:

    【解决方案7】:

    您的案例: 从 REST 角度来看,HTTP 400 是您案例的正确状态代码,因为发送 sales_tax 而不是 tax 在语法上不正确,尽管它是有效的 JSON。在将 JSON 映射到对象时,大多数服务器端框架通常都会强制执行此操作。但是,有些 REST 实现会忽略 JSON 对象中的新 key。在这种情况下,服务器端可以强制执行自定义 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 仍然是真正的响应。

    【讨论】:

      【解决方案8】:

      首先这是一个很好的问题。

      400 错误请求 - 当请求中缺少关键信息时

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

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

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

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

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

      【讨论】:

      • 422 表示语法有效,但内容无效。在需要 XML 的地方发送 JSON 意味着语法错误,因此在这种情况下 400 是正确的响应。
      • 正如 Dirk 所说,422 表示语法上有效的请求(可以解析和理解)但语义上无效
      • 400:由于语法无效(例如解析错误)而无法处理请求时; 422:由于无效数据(例如验证错误)而无法处理请求时。
      • 您的 422 示例无效,因为通过发送带有 application/xml 媒体类型的 json,正文自动在语法上不正确,响应应为 400。
      猜你喜欢
      • 2017-09-25
      • 2020-10-23
      • 1970-01-01
      • 2021-07-10
      • 2017-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多