假设我有一个采用整数作为参数的REST端点:

/makeWaffles?numberOfWaffles=3


在这种情况下,我希望数字为正数,因为我不能华夫饼的数量为负(而请求0个华夫饼是浪费时间)。所以我想拒绝任何不包含正整数的请求。我还想拒绝超过某个最大整数的请求(现在说的是MAX_INTEGER)。

如果有人请求华夫饼的数量为非正数,我应该返回HTTP 400 (错误请求)状态?我最初的想法是:对我来说,这不是有效的数字,无法完成请求。但是,RFC并未提及将业务规则作为抛出该规则的原因:


400(错误请求)状态代码表示服务器由于以下原因无法或不会处理该请求:被认为是客户端错误的内容(例如格式错误的请求语法,无效的请求消息框架或欺骗性的请求路由)。


业务规则不属于任何这些规则三个例子。它在语法上正确,结构正确,并且不是欺骗性的请求路由。

如果参数在语法上正确但违反了业务规则,我应该返回HTTP 400(错误请求)状态吗?还是有更适合返回的状态?

评论

相关:stackoverflow.com/questions/16133923/…

相关:我是否应该使用HTTP状态代码来描述应用程序级别的事件

#1 楼

这是一个很大的问题,考虑到HTTP返回代码的历史背景(似乎相互矛盾的定义),它仍然非常相关。即使在这个问题的答案中也存在矛盾的定义。可以按时间顺序进行澄清。

RFC 2616(1999年6月)


10.4.1 400错误的请求


/>由于语法
格式不正确,服务器无法理解该请求。未经
修改,客户端不应重复请求。




从该RFC开始,此状态代码专门仅用于语法无效的请求。用于语义验证的状态码中存在空白。因此,当RFC 4918出现时,新的代码诞生了。

RFC 4918(2007年6月)


11.2。 422无法处理的实体


422(不可处理的实体)状态代码表示服务器
了解请求实体的内容类型(因此,
415(不受支持的媒体类型)状态代码不合适),并且请求实体的
语法正确(因此,400(错误请求)
状态代码不合适),但无法处理所包含的
指令。例如,如果XML
请求正文包含格式正确(即,语法正确)但
语义上错误的XML指令,则可能发生此错误情况。



422不可处理实体的创建是为了填补4xx状态码原始规范中语义验证的空白。但是,在2014年又出现了另一个相关的RFC,将400泛化为不再专门针对语法。

RFC 7231(2014年6月,明显废除RFC 2616)


> 6.5.1。 400错误的请求


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




请注意,422说明中指出了原因400是不合适的,因为仅应针对错误的请求语法返回400(从RFC 2616开始)。但是,从RFC 7231开始,严格的语法错误定义不再适用于400。

回到当前的问题:尽管从技术上讲422更具体,但鉴于这种情况,我可以看到400或422用于API参数的语义验证。我不愿意在自己的API中使用422,因为在这一点上422的定义在技术上已经过时了(尽管我不知道是否在任何地方都正式认可了422)。在Fran的答案中引用的鼓励使用422的文章写于2012年,比RFC 7231阐明HTTP 400早了两年。请确保对彼此进行标准化。

#2 楼

我阅读了第一个答案,但并没有真正同意,因为至少在我的阅读中,一个错误的请求(400)表示:“我什至无法处理您的请求,因为某些根本上是错误的。”而且我发现了该帖子,为从IETF返回422提供了理由。

422无法处理的实体(WebDAV; RFC 4918)
请求很好-已形成但由于语义错误而无法遵循

这似乎是一个更适当的响应,因为您的请求格式正确,但未通过验证规则。

评论


我听说它被描述为“ 400表示语法错误,422表示语义错误”。

– Bojar
16年8月24日在20:44

所有x00代码都是“全部捕获”通用代码。 400不是不合适的,只是不够具体。

–杰克
16年8月24日在21:11

好的答案,但是@GoFree给出的答案对我来说更有意义。

– Ewerton
17年8月30日14:30在

有一个非常有力的理由返回所有人都知道的代码。绝对每个人都需要查找422,我敢打赌,大多数人仍然不知道该怎么做。

–西尔瓦纳(sylvanaar)
18-2-26在17:11

#3 楼

不,你不应该。 HTTP代码用于应用程序的HTTP层。业务规则是完全不同的层,并且是特定于应用程序的,因此您需要提出自己的“协议”。

想象一下发生了启示,您必须从HTTP协议切换为使用Pigeons。鸽子没有任何返回码,因此您需要更改业务层以适应这种情况。但是您的业务并没有真正改变,因此您无需更改业务层。它显示了这两个层(运输和业务)之间的紧密耦合。回到问题:您应该做的是返回“ 200 OK”,并带有一个描述请求发生了什么的正文。规范明确指出:

https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1。


200 OK


请求成功。响应返回的信息取决于请求中使用的方法,例如

POST描述或包含操作结果的实体;



您的HTTP请求成功了吗?是的,Web服务器知道如何处理该请求(例如,将其传递到应用程序的服务器部分)。然后,Web服务器将此请求传递到应用程序的服务器部分,该服务器部分接收POST的数据,对其进行处理(在您的情况下对其进行验证),然后将正常答案(在HTTP响应的主体中)返回给应用程序的客户端部分。来自应用程序服务器部分的答案可能是“很好,您发送给我的数据有效”或“很抱歉,您发送的数据无效”。而且,取决于应用程序的客户端部分来了解答案的含义。

PS:“ 400错误的请求”表示Web服务器不了解您要从中获得什么。这意味着应用程序的服务器部分甚至没有收到请求。或至少这就是它的意思:-)

编辑:我刚刚意识到,您正在执行GET请求,而不是POST。这是一个坏主意,因为GET不应更改应用程序的状态。 GET应该只是从服务器检索数据。但是在您的请求中,您实际上是在更改应用程序的状态,因此您实际上应该使用POST。

评论


是的,在这种情况下返回404很好。我并不是说服务器应该始终发送200 OK,并在正文中进行解释。

– GoFree
17 Mar 7'7 at 23:27

@Thomas Lauria我还没有看到RESTFUL API的正确实现。但是,REST API如今已成为流行语,因此每个公司都必须在不真正理解其背后的概念的情况下使用它(这个词,而不是技术)。是的,它在任何地方都以错误的方式使用。程序员通常创建的不是REST API,而是HTTP API或OVER HTTP API。实际上,HTTP本身就是少数几种不错的RESTFUL实现之一:)

– GoFree
19-2-15在10:56



是的,您期望请求成功是正确的。但是在运输层上!因为HTTP状态代码是传输协议的一部分(正如首字母缩写HTTP所暗示的)。不在业务层上。邮局不会告诉您信封内的纳税申报表是否有效。它只会告诉您信封上的地址是否有效。邮局像HTTP一样处理信封的运输,而不处理信封的内容。

– GoFree
19年7月2日在14:49



如果应用程序在响应正文中包含一个“错误”字段来描述任何业务级错误,例如输入值过高或过低或缺失,产品缺货等,则使用200-OK尤其合乎逻辑。

–罗兰
19年7月31日在10:42

只是增加了一些权重,如果HTTP层的数据没有问题,那么您不应该发送HTTP错误来指示错误。当您尝试调试错误时,这会导致巨大的问题,因为您已经使用400来验证业务逻辑,那么现在使用什么代码来验证传输层?

–托尼·切特姆(Tony Cheetham)
20年1月15日在15:20

#4 楼

是的,不遵循端点的隐含约定的输入是“某些东西被视为客户端错误”,并且应返回400。

如果业务规则与安全相关,则是例外。 (然后401 Unauthorized403 Forbidden会更好)。另外,如果发送400会泄漏有关某物存在的信息,则404 Not Found可能更合适。

#5 楼

不确定是否所有人都会同意,但是我们使用的是409-冲突。许多人认为409与系统状态更多的是冲突,但是我们接受这样的解释,即请求者可以修复超出接受范围的数据值,并且可以接受409的使用。422我认为作为请求是合理的格式正确,但无法按要求进行处理。我认为,如果您不希望执行大量答复,那么仅给出400条也是可以接受的。

评论


409表示“您试图放入的状态与另一个客户端试图放入的状态相冲突”,它用于阻止并发写入(例如,使用ETag)

–杰克
16年8月24日在21:12