我应该使用哪个状态代码进行失败的验证或无效的重复?

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

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

我看过http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html,但没有一个是正确的。

发送状态码时是否有常见做法?

681524 次浏览

对于输入验证失败:400错误请求+您的可选描述。这在“RESTful Web服务”一书中建议。重复提交:409冲突


2014年6月更新

相关规范曾经是RFC2616,它将400(Bad Request)的使用范围缩小到

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

因此,它可能被认为不适合语义错误。但不再是了;自2014年6月以来,相关标准rfc7231取代了之前的RFC2616,将400(错误请求)的使用更广泛地定义为

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

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

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

我推荐状态码422,“不可处理的实体”

11.2.422不可处理实体

422(不可处理实体)状态码意味着服务器理解请求实体的内容类型(因此415(不支持的媒体类型)状态码是不合适的),请求实体的语法是正确的(因此400(错误请求)状态码是不合适的),但无法处理包含的指令。例如,如果XML请求体包含格式良好(即语法正确)但语义错误的XML指令,则可能会出现这种错误情况。

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未修改也会对重复的请求做出可接受的响应。这类似于使用实体标记处理If-None-Match的标头。

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

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

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

数据库中的副本应该是409 CONFLICT

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

我对4xx代码这里进行了更长的解释。

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

200

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

混合HTTP状态代码和REST状态代码是错误

但是,我看到许多实现将它们混合在一起,许多开发人员可能不同意我的观点。

HTTP返回代码与HTTP Request本身相关。REST调用是使用超文本传输协议请求完成的,它的工作级别低于调用的REST方法本身。REST是一个概念/方法,它的输出是业务/逻辑结果,而HTTP结果代码是运输结果。

例如,当您调用 /users/时返回“404没有找到”是令人困惑的,因为它可能意味着:

  • URI错误(HTTP)
  • 未找到用户(REST)

“403禁止/拒绝访问”可能意味着:

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

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

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

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

相反,您可以使用一些选项返回200 HTTP代码:

  • 如果出现问题,JSON结果中的“错误”对象
  • 如果未找到记录,则为空JSON数组/对象
  • bool结果/成功标志与以前的选项相结合,以获得更好的处理。

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

wiki

2004年7月,英国电信运营商BT集团部署了Cleanfeed内容阻塞系统,它向任何请求返回404错误被互联网观察认定为潜在非法的内容基金会。其他ISP在同一时间返回HTTP 403“禁止”错误情况。使用虚假404错误作为手段的做法泰国和突尼斯也报道了隐藏审查。在突尼斯在2011年革命前审查制度非常严格,人们开始意识到虚假404错误的性质并创建了一个名为“Ammar 404”的虚构人物,代表“看不见的人”审查员”。

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

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

即使请求在逻辑上失败,Google也始终在其地理编码API中返回200作为状态码:https://developers.google.com/maps/documentation/geocoding/intro#StatusCodes

Facebook总是为成功的HTTP请求返回200,即使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请求,当状态代码为422时,您可能希望将新资源的URI发送回Location标头,而不是400

真实世界的例子肯定更复杂,但这应该非常有效。