我正在使用基于rest的API构建一个应用程序,并且已经到了为每个请求指定状态代码的地步。

我应该发送什么状态代码的请求失败验证或请求试图添加一个副本在我的数据库?

我已经在http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html上找过了,但是没有一个是对的。

发送状态码时有什么惯例吗?


对于输入验证失败:400坏请求+您的可选描述。这在“rest式Web服务”一书中得到了建议。 对于双重提交:409冲突


2014年6月更新

相关的规范曾经是RFC2616,它给出了400(坏请求)的使用范围相当狭窄

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

因此,可能有人认为它不适用于语义错误。但现在不是了;自2014年6月起,相关标准RFC 7231取代了之前的RFC2616,更广泛地使用400(坏请求)

服务器不能或 将不会处理请求由于某些东西被认为是 客户端错误


验证失败:403禁止(“服务器理解请求,但拒绝完成它”)。与流行的观点相反,RFC2616并没有说“403仅用于失败的身份验证”,而是说“403:我知道您想要什么,但我不会那样做”。这种情况可能是由于身份验证,也可能不是。 试图添加副本:409冲突(“由于与资源的当前状态冲突,请求无法完成。”)

你应该在响应头和/或正文中给出更详细的解释(例如,使用自定义头- X-Status-Reason: Validation failed)。


我推荐状态码422,"不可处理实体"

11.2. 422 Unprocessable Entity The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.


200,300,400,500都是很通用的。如果你想要普通的,400就可以了。

422被越来越多的api使用,甚至被开箱即用的Rails使用。

无论您为API选择哪种状态代码,总会有人不同意。但我更喜欢422,因为我认为“400 +文本状态”太一般了。此外,您没有利用json就绪的解析器;相比之下,带有JSON响应的422非常显式,可以传递大量错误信息。

说到JSON响应,我倾向于在这种情况下对Rails错误响应进行标准化,即:

{
    "errors" :
    { 
        "arg1" : ["error msg 1", "error msg 2", ...]
        "arg2" : ["error msg 1", "error msg 2", ...]
    }
}

这种格式非常适合表单验证,我认为就“错误报告丰富度”而言,表单验证是最复杂的情况。如果您的错误结构是这样的,那么它可能会处理您所有的错误报告需求。


状态代码304 Not Modified也会对重复的请求做出可接受的响应。这类似于使用实体标记处理If-None-Match的报头。

在我看来,@Piskvor的答案是更明显的选择,我认为是原始问题的意图,但我有一个替代方案,也是相关的。

如果希望将重复请求视为警告或通知,而不是错误,响应状态码304 Not Modified和标识现有资源的Content-Location头同样有效。当意图仅仅是确保资源存在时,重复的请求将不是错误,而是确认。请求并不是错误的,只是多余的,客户端可以引用现有的资源。

换句话说,请求是好的,但是由于资源已经存在,服务器不需要执行任何进一步的处理。


数据库中的副本应该是409冲突。

我建议使用422 UNPROCESSABLE ENTITY来处理验证错误。

我在这里对4xx代码做了更详细的解释。


Ember-Data的ActiveRecord适配器期望从服务器返回422个UNPROCESSABLE ENTITY。所以,如果你的客户端是用Ember.js编写的,你应该使用422。只有这样DS。错误将用返回的错误填充。当然,您可以将422更改为适配器中的任何其他代码。


200

啊…(309、400、403、409、415、422)……大量的答案试图猜测,争论和标准化什么是一个成功的HTTP请求和一个失败的REST调用的最佳返回代码。

将HTTP状态代码和REST状态代码混合使用是错误的。

然而,我看到许多实现混合了它们,许多开发人员可能不同意我的观点。

HTTP返回码与HTTP请求本身相关。REST调用是使用超文本传输协议(Hypertext Transfer Protocol)请求完成的,它的工作级别比调用的REST方法本身要低。REST是一种概念/方法,其输出是业务/逻辑结果,而HTTP结果代码是传输结果。

例如,当你调用/users/时返回“404 Not found”是令人困惑的,因为它可能意味着:

URI错误(HTTP) 没有找到用户(REST)

“403禁止/拒绝访问”可能是指:

需要特别许可。浏览器可以通过询问用户/密码来处理它。(HTTP) 服务器上配置的访问权限错误。(HTTP) 您需要进行身份验证(REST)

这个列表可能会继续出现“500服务器错误”(Apache/Nginx HTTP抛出错误或REST中的业务约束错误)或其他HTTP错误等……

从代码中,很难理解失败的原因是什么,HTTP(传输)失败还是REST(逻辑)失败。

如果HTTP请求物理上被成功执行,它应该总是返回200个代码,不管是否找到记录。因为URI资源是由HTTP服务器找到并处理的。是的,它可能返回一个空集。有可能收到一个空网页200作为HTTP结果,对吗?

相反,你可以返回200个HTTP代码和一些选项:

如果出现错误,JSON结果中的"error"对象 如果没有发现记录,则为空JSON数组/对象 一个bool result/success标志,结合前面的选项以获得更好的处理。

此外,一些互联网提供商可能会拦截您的请求并返回404 HTTP代码。这并不意味着您的数据找不到,而是在传输级别上出了问题。

从维基:

In July 2004, the UK telecom provider BT Group deployed the Cleanfeed content blocking system, which returns a 404 error to any request for content identified as potentially illegal by the Internet Watch Foundation. Other ISPs return a HTTP 403 "forbidden" error in the same circumstances. The practice of employing fake 404 errors as a means to conceal censorship has also been reported in Thailand and Tunisia. In Tunisia, where censorship was severe before the 2011 revolution, people became aware of the nature of the fake 404 errors and created an imaginary character named "Ammar 404" who represents "the invisible censor".

为什么不简单地这样回答呢?

{
  "result": false,
  "error": {"code": 102, "message": "Validation failed: Wrong NAME."}
}

谷歌总是在他们的地理编码API中返回200作为状态代码,即使在逻辑上请求失败:https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes

Facebook总是返回200成功的HTTP请求,即使REST请求失败:https://developers.facebook.com/docs/graph-api/using-graph-api/error-handling

很简单,HTTP状态码是用于HTTP请求的。REST API是你的,定义你的状态代码。


我得出的结论是尝试遵循这个规则:如果它表明客户端开发人员错误,那么使用400(坏请求)。否则,假设根本没有客户端验证,如果哑用户输入无效数据,则使用422(不可处理实体)。如果有疑问,最好使用422,或者使用更容易实现的版本。

这有助于开发人员了解到底是谁犯了错误,是他自己还是用户。

所谓笨用户,我指的是非技术用户。攻击者在这里不重要:如果您担心这个问题,您就不会首先使用HTTP状态码。:)

例如,如果您正在根据JSON模式验证JSON请求体,400是正确的选择(例如缺少键,关键字不匹配)。但是,如果您希望用户输入一个有效的电子邮件,那么您应该使用422(让我再说一遍,假设没有客户端验证)。

这对更好的分支逻辑也很有帮助。例如,在REST API的上下文中,假设您有一个调查响应端点,可能使用POST和PATCH方法。在这种情况下,如果客户端发送了一个无效的POST请求,您可能希望在Location报头中返回新资源的URI,用于状态码为422时,而不是用于400时。

真实世界的例子当然更复杂,但我认为这应该很管用。