400和422对数据POST的响应


355

我正在尝试使用正在使用的“类似REST”的API找出在不同情况下返回的正确状态代码是什么。假设我有一个端点,允许JSON格式的POST购买。看起来像这样:

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

如果客户寄给我“ sales_tax”(而不是预期的“ tax”),我应该返回什么。目前,我要退回400。但是,我开始对此提出质疑。我真的应该归还422吗?我的意思是,它是JSON(受支持),并且是有效的JSON,只是不包含所有必填字段。


Answers:


419

对于您的用例,400错误请求现在似乎是最好的HTTP / 1.1状态代码。

在提出问题时(和我的原始答案),RFC 7231并不是问题。当时我反对,400 Bad Request因为RFC 2616表示(重点是我的):

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

并且您描述的请求是语法有效的JSON(包含在语法有效的HTTP中),因此服务器的请求语法没有问题。

但是 作为评论李Saferite指出RFC 7231,它淘汰了RFC 2616,不包括限制

400(错误请求)状态代码表示服务器由于某些原因(例如格式错误的请求语法,无效的请求消息框架或欺骗性的请求路由)而被视为客户端错误,因此服务器无法处理该请求。


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

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

并且描述为422

422(不可处理实体)状态代码表示服务器理解请求实体的内容类型(因此415(不支持的媒体类型)状态代码不合适),并且请求实体的语法正确(因此400(错误请求) )状态代码不合适),但无法处理其中的说明。

(请注意对语法的引用;我怀疑7321也部分淘汰了4918)

这声音正是像您的情况,但万一有任何疑问,接着说:

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

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

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

可以选择在原始标准中使用错误代码(该代码未明确涵盖该情况)与从扩展中准确描述该情况的错误之间进行选择,我将选择后者。

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

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


但是从HTTP / 1.1开始,RFC 7231具有吸引力,因此只需使用即可400 Bad Request


5
您的回答(422)对我来说很有意义。这也是Rails(response_with)在由于验证错误而无法处理资源时使用的方法。
泰勒里克(Tyler Rick)2014年

11
请注意此处使用非WebDAV规范中的422:tools.ietf.org/html/rfc5789#section-2.2
Andrey Shchekin 2014年

4
只是作为更新,RFC 7231对更改语义的响应代码400进行了不同的描述。
Lee Saferite

5
抱歉,我更新了此答案以反映RFC中的更改,并且失去了一些清晰度。我会尝试重构。这几乎可以肯定是安全的使用422,但现在你应该用400
克里斯蒂安玻璃

2
我仍然认为规范可能要清晰得多。中给出的示例是客户做错事的明显案例。OP的情况也属于此类。但是,在某些情况下,“我理解您的要求,但我拒绝这样做,因为有一些反对它的商业规则”,这种情况并不是很明确。这并非完全是客户的错,因此按照相同的规范,实际上可能适用403:“但是,出于与凭据无关的原因,可能会禁止请求”。我宁愿为权限相关的东西使用单独的代码,而不是“无法完成”。
Thorarin

37

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

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

http://tools.ietf.org/html/rfc2616#section-10.4.1

422无法处理的实体由RFC 4918-WebDav定义。请注意,与400相比略有差异,请参见下面的引文。

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

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

http://tools.ietf.org/html/rfc4918#page-78

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

尝试将应用程序的每个部分“深入”映射到HTTP状态代码是一个错误;在大多数情况下,您想要的粒度级别要粗糙得多。如有疑问,在没有更好的适合时,可以使用通用状态代码200 OK,400错误请求和500内部服务错误

如何思考HTTP状态码


4
422代码是IANA注册中心iana.org/assignments/http-status-codes/http-status-codes.xhtml的一部分,因此任何IMHO都没有意义。无论如何,Facebook和Twitter REST API都会重塑自己的代码,并且不使用RFC / IANA标准。这样就可以了。
gotnkoa

15
第11节明确指出,它们已添加到整个规范中,而不仅仅是WebDav规范中:The following status codes are added to those defined in HTTP/1.1 [RFC2616].
Steve Tauber 2014年

8
仅仅因为代码被描述为WebDAV规范的一部分,并不意味着它是特定于WebDAV的!状态码应该是通用的。
好好对待您的mods 2014年

33

为反映截至2015年的状况:

从行为上讲,客户端和中介将对400和422响应代码进行相同的处理,因此实际上并不会对您使用的内容产生任何具体的影响

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

  • HTTPbis规范阐明了400的意图不仅仅是语法错误。现在使用更广泛的短语“表明服务器由于某种被视为客户端错误的原因而无法或不会处理请求”。
  • 422特别是WebDAV扩展,在RFC 2616或较新的HTTPbis规范中未引用。

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


4
403 Forbidden难道也不能用于这种情况吗?Quote:403(禁止)状态代码表示服务器可以理解请求,但拒绝对其进行授权...如果在请求中提供了身份验证凭据,则服务器认为它们不足以授予访问权限...但是,请求可能由于与凭据无关的原因而被禁止。 因此,看起来403可用于拒绝身份验证之外的请求。
垃圾收集器

1
@garbagecollector注意:“由于凭据之外的原因而被拒绝!! =”由于身份验证之外的原因而被拒绝。具体来说,有很多方法可以在不使用凭据的情况下对某人进行身份验证。
Knetic '17

@garbagecollector否,凭据表示身份验证(“您是谁”),失败时将为401。失败时授权(“您可以做什么”)为403。此处有完整说明:stackoverflow.com/a/6937030/137948 都不适用于OP的“缺少字段”情况,因为无论哪个用户尝试该错误,该错误都是相同的。我同意400是正确的答案。
谢泼德

27

案例研究:GitHub API

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

也许从知名的API复制是一个明智的主意:

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

发送无效的JSON将导致400错误的请求响应。

HTTP/1.1 400 Bad Request
Content-Length: 35

{"message":"Problems parsing JSON"}

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

HTTP/1.1 400 Bad Request
Content-Length: 40

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

发送无效字段将导致422无法处理的实体响应。

HTTP/1.1 422 Unprocessable Entity
Content-Length: 149

{
  "message": "Validation Failed",
  "errors": [
    {
      "resource": "Issue",
      "field": "title",
      "code": "missing_field"
    }
  ]
}

我认为这是正确且可以理解的答案。
LEMUEL ADANE

1
无法再投票了。希望获得更多支持的答案可以参考这一答案。规范(RFC,IANA)显然未能提供明确的定义和两者之间的区别。因此,答案归结为最佳实践,GitHub给了我们一个。
Alex Klaus

15

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

  1. 始终使用响应代码
  2. 在响应正文中包含尽可能多的其他信息,以帮助使用API​​的开发人员了解正在发生的事情。=

在每个人都说我这里没有对与错的答案之前,让我跳过一下,让我先解释一下我是如何得出结论的。

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

就像我在上面说的那样,决定因素是语法。如果请求的Content Type为application/json,则是,该请求在语法上有效,因为它是有效的JSON语法,但在语义上无效,因为它与预期的不匹配。(假设严格定义了使所请求的请求在语义上有效或无效的原因)。

另一方面,如果发送的请求具有更具体的自定义内容类型,例如application/vnd.mycorp.mydatatype+json,可能确切指定了期望的字段,那么我想说该请求在语法上可能很容易无效,因此返回400。

在这种情况下,由于密钥是错误的,而不是value,所以如果有关于有效密钥的规范则存在语法错误。如果没有有效密钥的规范,或者错误带有value,那么它将是语义错误。


答案很低估-感谢您措辞充分的解释。
puiu

正是我对此事的想法!我来自XML SOAP背景,而架构的概念只是深入我的血液和JSON文档中,而不是宣布它们的架构。对我来说,服务器是否“理解”请求。如果服务器不知道“ sales_tax”是什么,那么它就是400:“我不知道您给我发送了什么,但绝对不知道我想要什么。”
Aleksander Stelmaczonek'7

4

422无法处理的实体解释已更新:2017年3月6日

什么是422不可处理实体?

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

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

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

422(不可处理实体)状态代码表示服务器理解请求实体的内容类型(因此415(不支持的媒体类型)状态代码不合适),并且请求实体的语法正确(因此400(错误请求) )状态代码不合适),但无法处理其中的说明。

定义继续说:

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

400和422状态代码

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

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

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


1

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

422的理想方案:

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

422中400的情况:

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

在企业体系结构中,服务大部分部署在SOA,IDM等服务层上。它们通常为多个客户端提供服务,从非常老的本机客户端到最新的HTTP客户端。如果其中一个客户端不处理HTTP 422,则选项为要求客户端将所有人的响应代码升级或更改为HTTP 400。以我的经验,这几天很少见,但仍有可能。因此,在决定HTTP响应代码之前,始终需要仔细研究您的体系结构。

为了处理这种情况,服务层通常使用versioning或setup 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仍然是真正的响应,只要客户可以处理它。


1

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

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

例如,授权标头或内容类型标头。服务器必须完全了解该请求。这可能因服务器而异。

422无法处理的实体-无法解析请求正文时。

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

例如,Content-Type: application/xml当请求主体为JSON时。

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


5
422表示语法有效,但内容无效。在需要XML的地方发送JSON表示语法错误,因此在这种情况下,正确的响应为400。
德克

1
就像Dirk所说的那样422意味着语法上有效的请求(可以被解析和理解)但语义上是无效的
Jacek Obarymski

400:由于语法错误(例如解析错误)而无法处理请求时;422:由于无效数据(例如验证错误)而无法处理请求时。
Kitanotori

您的422的例子是无效的,因为通过与应用程序/ xml的媒体类型发送JSON,身体会自动在语法上是不正确的,响应应该是400
manemarron

-15

您实际上应该返回“ 200 OK”,并且在响应正文中包含一条有关已发布数据发生了什么的消息。然后由您的应用程序了解消息。

问题是,HTTP状态代码就是HTTP状态代码。这些仅在传输层具有意义,而在应用层则没有意义。应用程序层实际上甚至应该永远不知道正在使用HTTP。如果将传输层从HTTP切换到Homing Pigeons,则它不应以任何方式影响应用程序层。

让我给你一个非虚拟的例子。假设您爱上了一个女孩,而她爱着您,但她的家人搬到了一个完全不同的国家。她给您她的新蜗牛电子邮件地址。自然,您决定寄给她一封情书。因此,您写了一封信,将其放入信封中,在信封上写下她的地址,在上面盖章然后发送。现在让我们考虑这些情况

  1. 您忘了写街道名了。您将收到一封未打开的信,上面写有一条消息,指出地址格式不正确。您搞砸了请求,接收邮局无法处理它。这相当于收到“ 400错误请求”。
  2. 因此,您确定地址并再次发送信件。但是由于运气不好,您完全拼错了这条街的名称。您将再次收到一封信,并显示一条消息,指出该地址不存在。这相当于收到“ 404 Not Found”。
  3. 您再次固定该地址,这一次您设法正确写入该地址。您的女孩收到这封信,然后给您回信。相当于收到“ 200 OK”。但是,这并不意味着您会喜欢她在信中写的内容。这仅表示她已收到您​​的消息并为您回复。在打开信封阅读她的信之前,您不知道她是想念您还是想与您分手。

简而言之:返回“ 200 OK”并不意味着服务器应用程序对您来说是个好消息。这仅意味着它有一些新闻。

PS:422状态代码仅在WebDAV上下文中具有含义。如果您不使用WebDAV,则422与其他任何非标准代码完全相同,即没有。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.