400对422对数据POST的响应

Dav*_*d S 323 rest http-status-codes

我正在尝试使用我正在处理的"类似REST"的API来确定在不同场景下返回的正确状态代码.假设我有一个终点允许以JSON格式进行POST'ing购买.它看起来像这样:

{
    "account_number": 45645511,
    "upc": "00490000486",
    "price": 1.00,
    "tax": 0.08
}
Run Code Online (Sandbox Code Playgroud)

如果客户向我发送"sales_tax"(而不是预期的"税收"),我应该返回什么.目前,我要回400.但是,我已经开始质疑自己了.我应该真的回来422吗?我的意思是,它是JSON(支持)并且它是有效的JSON,它只是不包含所有必需的字段.

Kri*_*ass 381

400 Bad Request现在似乎是您的用例的最佳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(错误请求) )状态代码不合适)但无法处理包含的指令.

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

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

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

(将"XML"替换为"JSON",我想我们可以同意这是你的情况)

现在,有些人会反对RFC 4918是关于"Web分布式创作和版本控制的HTTP扩展(WebDAV)",并且你(大概)没有涉及WebDAV,所以不应该使用它.

鉴于在原始标准中使用明确不包括情况的错误代码与从描述情况的扩展中使用错误代码之间的选择,我会选择后者.

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

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


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

  • 请注意在非WebDAV规范中使用422:http://tools.ietf.org/html/rfc5789#section-2.2 (9认同)
  • 我道歉 - 我更新了这个答案,以反映RFC的变化并失去一些清晰度; 我会尝试重构.使用422几乎可以肯定*安全*,但现在你*应该*使用400. (4认同)
  • 就像更新一样,RFC 7231对响应代码400有不同的描述,可以改变语义. (3认同)
  • 难怪大家都很困惑。我还是很困惑。;-) (3认同)
  • 最令人困惑的答案。不确定有这么多赞成票 (3认同)
  • 你的答案(422)对我有意义.这也是Rails([respond_with](http://api.rubyonrails.org/classes/ActionController/Responder.html))在由于验证错误而无法处理资源时使用的. (2认同)
  • 422 是已知且可跟踪的代码:http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml 后续标准将考虑此代码,并且将来可能在 HTTP 中使用 422具有相同语义的 RFC 编码。当你有需要的时候就使用它。 (2认同)
  • 我仍然认为规范可能要清晰得多。中给出的示例是客户做错事的明确案例。OP的情况也属于此类。但是,在某些情况下,诸如“我理解您的要求,但我拒绝这样做是因为存在一些针对它的业务规则”之类的情况并没有那么明确。这并非完全是客户的错,因此按照相同的规范,实际上可能适用403:“但是,出于与凭据无关的原因,可能会禁止请求”。我宁愿为权限相关的东西使用单独的代码,而不是“无法完成”。 (2认同)
  • 我认为更改标准以适应当前状态码使用模式是很愚蠢的。这就像通过删除PUT和DELETE并将其替换为POST来更改REST原理一样,因为人们经常使用POST进行更新/删除操作。错误的请求现在告诉您,您使用错误的语法提出了请求,或者SERVER由于某种原因决定拒绝您的请求。我什至不相信这样的担忧! (2认同)

fil*_*p26 34

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

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

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

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

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

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

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

另见Mark Nottingham关于状态代码的帖子:

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

如何考虑HTTP状态代码

  • 第11节明确指出它们被添加到整个规范中,而不仅仅是在WebDav规范中:`以下状态代码被添加到HTTP/1.1 [RFC2616]中定义的那些. (13认同)
  • 仅仅因为代码被描述为WebDAV规范的一部分并不意味着它是特定于WebDAV的!状态代码应该是通用的. (6认同)
  • 422代码是IANA注册管理机构http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml的一部分,因此任何恕我直言都没有意义.无论如何,Facebook和Twitter REST API重新发明自己的代码,不使用RFC/IANA标准.所以你可以做到. (3认同)

Tom*_*tie 32

反映截至2015年的状况:

客户和中介机构对400和422响应代码的行为将被视为相同,因此它实际上并没有使用您所具有的具体差异.

但是我希望看到400目前使用得更广泛,而且HTTPbis规范提供的说明使得两个状态代码更合适:

  • HTTPbis规范阐明了400不仅仅是为了语法错误的意图.现在使用更广泛的短语"表示服务器不能或不会因为被认为是客户端错误而处理请求".
  • 422具体是WebDAV扩展,在RFC 2616或较新的HTTPbis规范中未引用.

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

  • 那么403 Forbidden是否也可以用于此背景?Quote:_ 403(Forbidden)状态代码表示服务器理解请求但拒绝授权...如果请求中提供了身份验证凭据,则服务器认为它们不足以授予访问权限....但是,请求可能由于与凭证无关的原因而被禁止.所以看起来403可用于拒绝身份验证之外的请求. (4认同)
  • @garbagecollector 请注意“由于 _credentials_ 之外的原因被拒绝”!=“由于 _authentication_ 之外的原因被拒绝。” 有很多方法可以在不使用凭据的情况下对某人进行身份验证,特别是。 (2认同)

Cir*_*四事件 16

案例研究: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"}
Run Code Online (Sandbox Code Playgroud)

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

HTTP/1.1 400 Bad Request
Content-Length: 40

{"message":"Body should be a JSON object"}
Run Code Online (Sandbox Code Playgroud)

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

HTTP/1.1 422 Unprocessable Entity
Content-Length: 149

{
  "message": "Validation Failed",
  "errors": [
    {
      "resource": "Issue",
      "field": "title",
      "code": "missing_field"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为这个答案并不明确。缺少字段可能是尚未发送的字段,这对我来说显然是 400,因为应用程序无法理解此有效负载,它违反了合同。恕我直言,400 更适合格式不正确的 JSON、具有不同键名称(违反合同)的 JSON 以及一个或多个字段内容来自另一种类型的 JSON,比方说,您期望一个 int 并得到一个目的。即使非空约束也可以出现在两个状态代码中,如果字段根本没有发送(并且大多数框架将其理解为空),则为 400;如果已发送但具有空值,则为 422。 (5认同)
  • 不能再点赞了。希望更多赞成票的答案会提到这一点。规范(RFC、IANA)显然未能提供明确的定义和两者之间的区别。因此,答案归结为最佳实践,GitHub 为我们提供了一个。 (3认同)
  • 如果 JSON 格式错误,即无效的必填字段,则返回 400。如果 JSON 缺少处理请求可能需要的可选字段,则返回 422。如果 JSON 包含有效字段,但字段的值阻止请求被执行。已处理(例如资金不足),然后是 422。对我来说 400 和 422 之间的主要区别是 422 服务器理解请求,但由于值本身(而不是值的类型)而无法完成请求。400 表示服务器不会尝试处理请求,因为 JSON 不正确 - 字段/值类型无效。 (3认同)

cde*_*zaq 14

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

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

在每个人都跳到我面前说这里没有正确或错误的答案之前,让我解释一下我是如何得出结论的.

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

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

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

在有问题的情况下,由于密钥错误,而不是,如果存在有效密钥的规范,则存在语法错误.如果没有有效密钥的规范,或者错误带有值,那么这将是语义错误.

  • 正是我对此事的想法!我有 XML SOAP 背景,模式的概念已经融入我的血液中,而 JSON 文档则不要公布它们的模式。对我来说,问题在于服务器是否“理解”该请求。如果服务器不知道“sales_tax”是什么,那么它只是 400:“我不知道你发给我的是什么,但绝对不是我想要的。”。 (2认同)