如果参数在语法上正确但违反业务规则,是否应该返回HTTP 400(错误请求)状态?


56

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

/makeWaffles?numberOfWaffles=3

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

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

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

业务规则不属于这三个示例中的任何一个。从语法上讲,它是正确的,并且具有正确的框架,并且不是欺骗性的请求路由。

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



Answers:


38

这是一个很大的问题,考虑到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 Unprocessable Entity,以填补4xx状态码原始规范中语义验证的空白。但是,2014年又出现了另一个相关的RFC,将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早了两年。请务必对其中一项进行标准化。


42

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

来自IETF

422不可处理实体(WebDAV; RFC 4918)请求的格式正确,但由于语义错误而无法遵循

由于您的请求格式正确,但未通过您的验证规则,因此这似乎是更合适的响应。


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

33
所有x00代码都是“全部捕获”通用代码。400不是不合适,只是具体程度较低。
杰克

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

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

8

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

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


8

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

假设发生了一个启示,您必须从HTTP协议切换为使用Pigeons。鸽子没有任何返回码,因此您需要更改您的业务层以适应这种情况。但是您的业务并没有真正改变,因此您无需更改业务层。它显示了这两层(运输和业务)之间的紧密耦合。

回到问题:您应该做的是返回“ 200 OK”,并显示一个描述请求发生了什么的正文。规范明确指出:

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

200 OK

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

发布一个描述或包含操作结果的实体;

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

PS:“ 400错误的请求”表示Web服务器无法理解您想要的内容。这意味着应用程序的服务器部分甚至没有收到请求。或至少这就是它的意思:-)

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


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

到目前为止,我看到的更好的解释。我也有同样的问题,似乎所有单词都与我和你觉得有所不同@GoFree
Ewerton

@GoFree这是重新考虑API设计的一个很好的答案。但是不是这样吗,当我们使用REST API时,我们将HTTP及其响应代码用作业务规则层的重要组成部分吗?
Thomas Lauria

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

1
使用200-OK是特别合乎逻辑的,如果应用程序包括在响应体的“错误”字段来描述任何一个企业级的错误,如输入值过高或过低或缺失,产品缺货,等
罗兰

-3

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


5
409表示“您试图放入的状态与另一个客户端试图放入的状态冲突”,这是为了阻止并发写入(例如,使用ETag)
Jack
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.