对数据POST的响应是400 vs 422

我正在试图弄清楚在不同的情况下使用“rest -like”返回的正确状态代码是什么。我正在做的API。假设我有一个端点,允许以JSON格式POST'ing购买。它是这样的:

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

如果客户发送给我“sales_tax"(而不是预期的“税”)。目前,我要返回400分。但是,我开始质疑自己。我真的应该退回422吗?我的意思是,它是JSON(这是受支持的),它是有效的JSON,它只是不包含所有必需的字段。

531248 次浏览

400错误请求是你用例的HTTP状态代码。该代码由HTTP/0.9-1.1 RFC定义。

由于格式错误,服务器无法理解请求 语法。客户端不应该重复请求 修改。< / p >

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

422不可处理实体由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 当没有更好的匹配时服务错误.

.

.

关于HTTP状态码的思考

400错误请求现在似乎是你用例中最好的HTTP/1.1状态代码。

在你提问的时候(和我最初的答案),RFC 7231不是一个东西;在这一点上,我反对400 Bad Request,因为RFC 2616说(强调我的):

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

你描述的请求是语法上有效的JSON,封装在语法上有效的HTTP中,因此服务器对请求的语法没有任何问题。

__abc0 __abc1, __abc2:

400(坏请求)状态码表示服务器不能或不愿处理请求,原因是客户机错误(例如,格式错误的请求语法、无效的请求消息框架或欺骗性的请求路由)。


然而,在重新措辞之前(或者如果你想争辩RFC 7231现在只是一个提出了标准),422 Unprocessable Entity对你的用例来说似乎不是一个不正确的 HTTP状态代码,因为作为RFC 4918的介绍说:

而HTTP/1.1提供的状态码足以 描述WebDAV方法遇到的大多数错误条件 是一些不能完全归入现有类别的错误。 该规范定义了为WebDAV开发的额外状态代码

.方法(第11节

422的描述说:

422(不可处理实体)状态码表示服务器 理解请求实体的内容类型(因此是 415(不支持的媒体类型)状态码不合适) 请求实体的语法是正确的(因此是400(坏请求) 状态码不合适),但无法处理包含的 指令。< / p >

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

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

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

(取代“XML"与“JSON"我想我们可以同意这是你的情况)

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

如果要在使用原始标准中明确不包含该情况的错误代码和使用来自扩展的准确描述该情况的错误代码之间做出选择,我会选择后者。

此外,RFC 4918 Section 21.4指的是IANA超文本传输协议状态码注册表,其中可以找到422。

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


但在HTTP/1.1中,RFC 7231具有牵引力,所以只需使用400 Bad Request!

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

  1. 一致地使用响应代码
  2. 在响应体中包含尽可能多的额外信息,以帮助使用API的开发人员弄清楚发生了什么

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

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

如上所述,决定因素是语法的含义。如果请求是以application/json的内容类型发送的,那么是的,请求是有效的语法,因为它是有效的JSON语法,但不是有效的在语义上,因为它不匹配预期的内容。(假设有一个严格的定义,什么使问题中的请求在语义上有效或无效)。

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

在这种情况下,由于关键是错误的,而不是价值,因此有一个关于有效键的语法错误如果有规范的话如果没有规格说明为有效键,或错误是一个值,则将是语义错误。

为反映截至2015年的状况:

从行为上讲,客户端和中介体对400和422响应代码的处理是一样的,所以实际上你使用哪一个响应代码并没有混凝土的区别。

然而,我希望看到400目前被更广泛地使用,而且HTTPbis规范提供的澄清使它成为两个状态代码中更合适的一个:

  • HTTPbis规范明确了400的意图,不只是用于语法错误。更广泛的短语“;表明服务器不能或不愿处理请求,由于某些被认为是客户端的错误”。现在使用。
  • 422是一个特定的WebDAV扩展,在RFC 2616或更新的HTTPbis规范中没有引用。

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

从REST的角度来看,你的情况: HTTP 400是正确的状态代码,因为发送sales_tax而不是tax在语法上是不正确的,尽管它是一个有效的JSON。在将JSON映射到对象时,大多数服务器端框架通常会强制执行这一点。然而,有一些REST实现忽略JSON对象中的new 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仍然是一个真正的响应,提供客户端可以处理它。

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

什么是422不可处理实体?

但是,当请求是格式良好时,会出现422状态码 对于语义错误是无法处理的。此HTTP状态为 在RFC 4918中引入,更专门针对HTTP Web分布式创作和版本控制(WebDAV)扩展 有一些关于开发者是否 应该返回一个400 vs 422的错误给客户端(更多的区别 介于以下两种状态之间)。然而,在大多数情况下,这是同意的 如果你支持WebDAV, 422状态才会返回 功能。< / p > 从section中获取的422状态代码的逐字定义 RFC 4918中的11.2可以在下面阅读

422(不可处理实体)状态码表示服务器 理解请求实体的内容类型(因此是 415(不支持的媒体类型)状态码不合适) 请求实体的语法是正确的(因此是400(坏请求) 状态码不合适),但无法处理包含的 指令。< / p >

这个定义接着说:

例如,如果XML请求体 包含格式良好(即语法正确),但语义错误

. XML

400 vs 422状态码

糟糕的请求错误使用400状态码 返回给客户端,如果请求语法错误,则包含 无效的请求消息帧,或具有欺骗性的请求路由。 这个状态代码可能看起来非常类似于422不可处理 然而,实体状态的一小部分信息表明 它们的区别在于请求实体的语法 422错误是正确的,而生成的请求的语法

. 400错误是不正确的 422状态的使用应该只保留在非常特殊的情况下 用例。在大多数其他情况下,客户端错误已经发生 对于格式错误的语法,应该使用400 Bad Request状态

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

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

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

例如:授权头或内容类型头。这是服务器理解请求所必需的。这可能因服务器而异。

422不可处理实体-当请求体不能被解析时。

这比400要轻。请求已经到达服务器。服务器已经确认请求的基本结构是正确的。但是无法解析或理解请求主体中的信息。

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

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

案例研究:GitHub API

https://docs.github.com/en/rest/overview/resources-in-the-rest-api#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 Unprocessable Entity响应:

HTTP/1.1 422 Unprocessable Entity
Content-Length: 149


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