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


54

我处理过的几台服务器将返回HTTP 200,以请求客户端应认为失败的请求,其中的内容为“ success:false”。

在我看来,这似乎不是HTTP代码的正确实现,尤其是在身份验证失败的情况下。我已经很简洁地阅读了HTTP错误代码,其中“ 4xx”指示在更改之前不应该再次发出请求,而“ 5xx”指示该请求可能有效或无效,可以重试,但未成功。在这种情况下,200:登录失败,或200:找不到该文件,或200:缺少参数x,这肯定是错误的。

另一方面,我可以看到有人争论说“ 4xx”应仅表示请求的结构性问题。因此,这很适合返回200:错误的用户名/密码,而不是未经授权的401,因为允许客户端进行请求,但是恰好是错误的。这个论点可以概括为:如果服务器能够处理请求并做出确定,则响应代码应为200,并且由客户端检查主体以获取更多信息。

基本上,这似乎是一个优先事项。但这并不令人满意,因此,我想知道,如果有人有理由说明这些范例中的任何一个更为正确。


9
success: false表示请求失败,您就知道了。那应该是500。诸如您错误的用户名/密码之类的东西就是401。这并不是很模糊。
皮特2015年


4
我认为这是可以引发宗教战争的问题之一。对于RESTful API,答案很明确,但是在其他类型的API中,HTTP仅被视为传输层,在这种情况下,应用程序错误不应渗漏到该层。
弄死了机器人

5
当我真的不确定要返回什么http状态时,总是很想念418“我是茶壶”。
joshp

1
一个示例是多个(批处理)请求和响应。批处理不是一件轻松的事情;但是实际的效率问题通常需要对批处理问题提供一些支持,而不是优雅的问题。
rwong 2015年

Answers:


35

有趣的问题。

基本上,我们可以将其简化为按照类似于OSI层的术语对事物进行分类的正确方法。HTTP通常定义为应用程序级别协议,而HTTP实际上是通用的客户端/服务器协议。

但是,实际上,服务器几乎总是中继设备,客户端是Web浏览器,负责解释和呈现内容:服务器只是将内容传递给任意应用程序,而应用程序会发回任意脚本,浏览器负责执行。HTTP交互本身(请求/响应形式,状态代码等)主要是如何有效地请求,提供服务和呈现任意内容,而不会造成干扰。实际上,许多状态代码和标头都是为此目的而设计的。

尝试搭载HTTP协议来处理特定于应用程序的流的问题在于,您剩下两个选择之一:1)您必须使请求/响应逻辑成为HTTP规则的子集;或2)您必须重用某些规则,然后关注点分离趋于变得模糊。起初看起来很干净,但是我认为这是您随着项目的发展而后悔的那些设计决策之一。

因此,我要说的是,最好明确协议的分离。让HTTP服务器和Web浏览器做好自己的事情,并让应用程序做自己的事情。该应用程序需要能够发出请求,并且需要响应-其关于如何请求,如何解释响应的逻辑比HTTP透视图复杂(或更少)。

值得一提的是,这种方法的另一个好处是,应用程序通常应该不依赖于底层的传输协议(从逻辑的角度来看)。HTTP本身在过去已经发生了变化,现在在SPDY之后,我们有了HTTP 2。如果您仅将您的应用视为HTTP功能插件,那么当新的基础架构接管时,您可能会陷入困境。


8
非常有见地。此处最强的参数是HTTP状态代码与应用的返回值之间的(阻抗)不匹配。从长远来看,这可能成为一场噩梦。此外,我强烈支持将传输(HTTP)与有效负载(应用程序数据)之间的关注点分离。如果您错误输入服务端点的URL,则会收到404。如果您向服务询问不存在的项目,则会收到特定于应用程序的消息(也许还包含其他信息,可以用来解决问题)。

2
如果您输入错误的URL,您甚至可能没有找到正确的服务器,然后可能发生任何事情。
gnasher729

这是一个很好的细微差别。我认为HTTP成为伪传输层的问题是做出决定的真正问题。当您有一个nginx或apache服务器代理一个nodejs服务器时,我最经常遇到这个问题。代理服务器已经具有用于发送这些代码的规则,而问题就变成了后端是否符合标准。在某些情况下,可能出于设计原因发送错误代码,因为nginx可能会将其解释为“后端向下”。
卡根·马特森

4
我同意。HTTP 200响应中报告的应用程序层错误没有问题。200表示HTTP请求/响应本身是成功的,没有说明其内容或当时被调用的应用程序层语义。
与莫妮卡(Monica)进行的轻度比赛

22

这个问题是基于观点的,但是无论如何。

我的看法是200可以解决“软错误”。当涉及到构建API时,我尝试区分这些错误和“硬错误”。

“软错误”的状态码为200,但包含错误说明和成功状态false。仅当结果“符合预期”时才会发生“软错误”,但从严格意义上讲不会成功。

重要的是要注意,“软错误”更多地是对实现者的提示。因此,重要的是还提供有关错误的更多信息,例如人类可读的错误消息和/或可用于向最终用户提供反馈的某种代码。这些错误为实现者(和最终用户)提供了有关服务器端发生的情况的更多信息。

例如,假设您有一个具有搜索功能的API,但是在搜索过程中不会产生任何结果。这不是错误的,但也不是“成功”,并不是严格意义上的定义。

格式化为JSON的示例:

{
    "meta" {
        "success": false,
        "message": "Search yielded no results",
        "code": "NORESULTS"
    }
    "data": []
}

另一方面,“硬错误”将带有建议用于该错误的状态代码。用户未登录?– 403 /401。输入格式错误?– 400.服务器错误?– 50倍。等等。

同样,它有点基于意见。某些人想平等对待所有错误,“硬错误”处理所有错误。没有搜索结果?那是404!在硬币的另一侧,没有搜索结果?–这是预期的,没有错误。

例如,要考虑的另一个重要因素是您的体系结构。如果您使用JavaScript XHR请求和jQuery或AngularJS与API进行交互。这些“硬错误”必须通过单独的回调进行处理,而“软错误”可以通过“成功”回调进行处理。没有破坏任何东西,结果仍然是“按预期”。客户端代码然后可以查看成功状态和代码(或消息)。并将其打印给最终用户。


2
实际上,将其完全归类为API级别的错误是一个奇怪的决定。即使客户可以根据自己的判断将其归类为用户级别的意外事件。
Deduplicator

1
必须考虑很多因素。这一切都取决于API的实现。同样,它也是基于观点的,并且还取决于API定义为“成功”和/或“错误”的内容。该"success": false-flag是更多的是一丝实施者有什么地方了。通常,它应该带有内部状态代码。不论"code": "NORESULTS"是数字代码还是API的创建者。大部分都在那儿,因此实现API的人都可以推断出服务器上发生的事情的信息。
死于maus

15

API有两个方面:实施API的努力,以及所有客户端正确使用API​​的努力。

作为客户端的作者,我知道当我向Web服务器发送请求时,我可能会收到错误(从未正确地与服务器交谈)或收到带有状态码的回复。我必须处理错误。我必须处理好回应。我必须处理预期的,有据可查的“不良”回复。我必须处理其他任何回来的事情。

在设计API时,您应该查看客户端最容易处理的内容。如果客户端发送格式正确的请求,并且您可以执行请求所要求的操作,那么您应该给出200范围内的答案(在某些情况下,该范围内200以外的数字是适当的)。

如果客户询问“给我所有类似...的记录”,并且为零,那么成功的200和零记录的数组是完全合适的。您提到的情况:

“登录失败”通常应为401。“找不到文件”应为404。“缺少参数x”应为500左右(实际上,如果服务器确定请求是错误的,则为400; 500)如果服务器完全被我的请求弄糊涂了,不知道发生了什么)。在这种情况下,返回200是没有意义的。这仅意味着作为客户的作者,我不能只看状态码,还必须研究答复。我不能只说“状态200,太好了,这是数据”。

特别是“参数缺失”-这是我永远不会处理的。这表示我的要求不正确。如果我的请求不正确,我将没有备用来解决该错误的请求-我会发送正确的请求开始。现在,我不得不处理它。我得到200,必须检查是否有“参数缺失”的答复。那是糟糕的。

最后,有一打或两个状态码可以处理许多不同的情况,您应该使用它们。


3
连接到API时,我个人宁愿连接到有效端点时在“找不到文件”上获得200,因为这样我的HTTP处理不必渗入处理API的层上。
whatsisname 2015年

4
“缺少参数x”应为400 BAD_REQUEST,因为它是客户端做错了什么。对于服务器执行错误操作的情况,应保留500 INTERNAL_SERVER_ERROR。500表示客户端可能可以重试。400表示有人应该去修理客户。

1
如果要编写RESTful接口,则URL标识特定对象,因此404是合适的。从概念上讲,它是/customers/premium/johndoe.json指不在数据库中的客户,并且/files/morefiles/customers.html是指不在文件系统上的页面的客户。

@whatsisname您的意思是有道理的,因为尚不清楚是端点损坏还是资源不存在。您还可以争论端点是否有效,该地址处没有资源,因此404在两种情况下a 都是正确的。
皮特

2
我未曾提及的一件事是,当您将应用程序错误附加到HTTP状态代码上时,您可能会丢失信息。如果该应用仅返回404,而您没有返回其他任何信息,则您不知道是因为您的API返回了404,还是因为服务器找不到该文件。这可能会增加调试步骤。
AmadeusDrZaius '16
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.