是否应使用HTTP状态代码来表示服务器上的业务逻辑错误?


20

对于客户端(浏览器中的JS)与服务器通信的一些API设计,我处在一个十字路口。由于有效的安全锁定,我们使用HTTP 409冲突来表示操作失败。安全锁可以防止开发人员意外更改我们客户的生产系统。我的任务是在客户端上更优雅地处理409s,以指示为什么特定的API调用失败。

我的解决方案是包装我们的任何AJAX调用的失败处理程序,当由于409导致某些操作失败时,它将在客户端上显示通知-一切都很好,并且可以与使用相同机制的其他4XX和5XX错误一起使用。

出现问题时,我们的一个路由处理程序在遇到业务逻辑错误时以409s响应-我的AJAX包装器报告安全锁已打开,而客户端的现有故障处理程序报告了(它认为)问题是基于主体的回应。一个简单的解决方案是更改处理程序的响应或用于表示安全锁的状态代码。

这使我走到了十字路口:HTTP状态代码是否应该甚至用来表示业务逻辑错误?这个问题解决了我面临的同一问题,但是并没有获得太大的吸引力。正如链接答案中所建议的那样,我倾向于使用HTTP 200 OK以及适当的正文来表示业务逻辑中的失败。

有人在这里有什么强烈的意见吗?有谁能说服我这是代表失败的错误方式?


3
我不愿发表我的简单意见作为答案。简而言之:我通常避免使用HTTP状态代码来表示业务错误。它们应仅与客户端和服务器之间的通信状态有关。用于返回验证或业务逻辑错误的合适状态码将是400 Bad Request。分离的原因是因为您对全球标准的偏离可能会使将来的系统,开发人员或文档阅读者感到困惑。
伊沃·库曼斯

@IvoCoumans:请给这个^一个答案,以便我投票赞成。400 Bad Request因为一揽子HTTP代码似乎最好将业务逻辑错误作为一个类来涵盖。
9000

个人喜好,但我倾向于400 Bad Request在数据丢失或无法读取/解析时使用。也就是说,请求数据本身在某种程度上是不好的。
Kasey Speakman'2

请进一步解释“业务逻辑错误”的含义。那是非常模糊的。您是说无效的输入符合(正确的)数据验证检查,在其他时间点可能有效但在当前状态下无效的输入,还是在业务逻辑中拒绝有效输入的错误?
jpmc26 2009年

@ jpmc26我故意含糊其词,因为这是一个普遍的问题。服务器很好地处理了该请求,但认为查询/断言没有意义。
Joe Shanahan

Answers:


19

凯西(Kasey)涵盖了重点。

任何网络api中的关键思想:您正在调整域以使其看起来像文档存储。GET / PUT / POST / DELETE等都是与文档存储进行交互的所有方式。

因此,考虑使用什么代码的一种方法是了解文档存储中的类似操作以及该类似情况下的故障情况。

2xx完全不合适

状态代码的2xx(成功)类表示已成功接收,理解并接受了客户的请求。

5xx也不合适

状态代码的5xx(服务器错误)类表示服务器知道它已错误

在这种情况下,服务器没有犯错;它知道您目前不应该以这种方式修改该资源。

业务逻辑错误(这意味着业务不变量当前不允许进行建议的修改)可能是409

409(冲突)状态代码表示由于与目标资源的当前状态冲突而无法完成请求。此代码用于用户可能能够解决冲突并重新提交请求的情况。服务器应该产生一个有效载荷,该载荷包括足够的信息供用户识别冲突的根源。

请注意最后一点-409响应的有效负载应将有关发生问题的信息传达给用户,并且理想情况下应包括超媒体控件,这些控件可将用户引导至可以帮助解决冲突的资源。

我的解决方案是包装我们的任何AJAX调用的失败处理程序,当由于409导致某些操作失败时,它将在客户端上显示通知-一切都很好,并且可以与使用相同机制的其他4XX和5XX错误一起使用。

我会指出这是问题所在;您在客户端的实现假定状态码足以确定问题。相反,您的客户端代码应检查有效负载,并根据可用信息进行操作。

毕竟,就是文档存储如何做到这一点

409  Conflict

your proposed change has been declined because ${REASON}.  
The following resolution protocols are available: ${LINKS[@]})

同样的方法400 Bad Request也可以接受;大致翻译为“您的请求存在问题。我们不会费心找出最适合的状态码,因此您可以开始。有关详细信息,请参见有效负载。”

我将使用422。输入有效,因此400不是正确的错误代码,无法使用

WebDAV规范包含此建议

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

我不认为这很匹配(尽管我同意这会引起一些疑问400)。我的解释是422“您发送了错误的实体”,409而“您在错误的时间发送了实体”。

换句话说,422指示孤立考虑的请求消息有问题,其中409指示请求消息与资源的当前状态冲突。

Ben Nadal对422的讨论可能会有用。


5
您正在调整自己的领域,使其看起来像是文档存储 ” –我很希望看到人们阅读此书,并他们决定(或反对)REST 之前充分理解所有的结果和含义。真。
JensG

在我看来,“业务逻辑错误”听起来像是“无效输入”,通常没有输入错误,因此通常通常是400。如果不是无效的输入,则表明服务器存在错误,建议输入500。您的答案似乎过多地假设了“业务逻辑错误”的性质。
jpmc26 2009年

我将使用422。输入有效,因此400不是要使用的正确错误代码
Konrad,

19

以我的经验,HTTP错误代码不足以表示业务错误。但是,它们对于表示错误类别很有用。

因此,我的建议是将HTTP错误代码用于错误类别,但为业务逻辑故障选择特定的错误(例如409 Conflict ... 200 OK在这里会产生误导),并在响应中包括指示特定业务错误的数据。确保这是响应内容的一部分,而不是状态文本,因为某些浏览器会忽略自定义状态文本。我喜欢使用的语言具有联合类型,可以方便地表示消息。但是您也可以为错误情况定义字符串常量。

例子

// error with text response
409 Conflict "safety_lock_engaged"
409 Conflict "customer_not_eligible_for_selected_discount"
// warning with JSON response
202 Accepted { "backorderedProductIds": [ 37, 476 ] }

高于400的4xx状态代码具有非常特殊的含义。如果您的案件没有特别涵盖,请选择400。
jpmc26 2009年

@ jpmc26如果我不以这种方式使用状态代码,则永远不会使用它们。但是,请随时以正确正确的方式在回答中使用它们。
Kasey Speakman

从某种意义上说,你是对的。他们从未使用过。在大多数应用程序中,为特定代码选择的含义似乎并不是很常见的用例。没关系。我们也有很多我们从不编写代码来捕获的异常。
jpmc26 2013年

@ jpmc26好异常并不是最好的模式。但是可以,请继续。
Kasey Speakman

不抛出或捕获特定的异常类型,就像从未使用过特定的HTTP代码或任何其他错误代码。我认为这很明显。异常模型是否“最佳”与这一点完全无关。
jpmc26

5

通常,我会避免使用HTTP状态代码来表示特定的业务逻辑错误。这是因为它们已经具有全球标准定义的语义。其他系统,新开发人员等会因您偏离标准而感到困惑。

我在最近的类似研究中发现,在400 Bad Request验证错误等情况下,通常接受使用该方法。这样,您对所有业务逻辑错误使用一个状态代码。

顺便说一句,409当您在编辑资源并尝试再次保存它时更改了资源时,应使用该命令。


4

您可以使用“错误请求”,并包括违反的业务规则的ID,以及响应正文中的更多详细信息。


我不知道这是否决的乳清。公司可以通过这种方式返回业务异常。
Skadoosh
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.