验证失败或重复无效的 REST HTTP 状态代码

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

对于未通过验证的请求,或者请求试图在数据库中添加重复项的情况,我应该发送什么状态代码?

我已经浏览了http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html,但似乎都不对。

发送状态代码时是否有惯例?

答案

对于输入验证失败: 400 错误的请求 + 您的可选描述。在 “ RESTful 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 无法处理的实体

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", ...]
    }
}

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

数据库中的重复项应为409 CONFLICT

我建议对验证错误使用422 UNPROCESSABLE ENTITY

我在这里给出了 4xx 代码的详细说明: http : //parker0phil.com/2014/10/16/REST_http_4xx_status_codes_syntax_and_sematics/

200

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

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

但是,我看到许多实现混在一起,许多开发人员可能不同意我的看法。

HTTP 返回码与HTTP Request本身有关。 REST 调用是使用超文本传输协议请求完成的,并且其工作级别比调用的 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 结果中的 “错误” 对象
  • 空 JSON 数组 / 对象(如果找不到记录)
  • 布尔结果 / 成功标志,与以前的选项结合使用,可实现更好的处理。

另外,某些互联网提供商可能会拦截您的请求并向您返回 404 HTTP 代码。这并不意味着未找到您的数据,但是在传输级别是有问题的。

维基

2004 年 7 月,英国电信提供商 BT Group 部署了 Cleanfeed 内容阻止系统,该程序将对 Internet Watch Foundation 认定为潜在违法的任何内容请求返回 404 错误。在相同情况下,其他 ISP 返回 HTTP 403“禁止” 错误。泰国和突尼斯也有报道采用伪造的 404 错误作为掩盖审查的手段。在突尼斯,2011 年革命之前审查制度很严厉,人们开始意识到伪造的 404 错误的性质,并创建了一个假想的人物,名为 “Ammar 404”,代表 “无形的审查者”。

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

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

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

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

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

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

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

在我看来,@ Piskvor 的答案是最明显的选择,我认为这是原始问题的意图,但我有另一种选择也很重要。

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

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