64

HTTP/1.1 规范 (RFC 2616)状态码 400, Bad Request (§10.4.1)的含义有以下说法:

由于语法错误,服务器无法理解该请求。客户端不应该在没有修改的情况下重复请求。

如今,在一些基于 HTTP 的 API 中似乎有一种普遍的做法,即使用 400 来表示请求的逻辑错误而不是语法错误。我的猜测是 API 这样做是为了区分400(客户端诱导)和500(服务器诱导)。使用 400 表示非语法错误是否可以接受或不正确?如果可以接受,是否有关于 RFC 2616 的带注释的参考,可以更深入地了解 400 的预期用途?

例子:

4

8 回答 8

65

想到状态 422(RFC 4918,第 11.2 节):

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

于 2011-01-24T19:12:48.650 回答
19

截至目前,旨在取代 RFC 2616 并使之过时的HTTPbis规范的最新草案指出

400(错误请求)状态码表示服务器不能或不会处理请求,因为接收到的语法无效、无意义或超出服务器愿意处理的某些限制。

该定义当然仍会发生变化,但它认可了广泛使用的以 400 响应逻辑错误的做法。

于 2013-06-25T09:21:00.563 回答
6

HTTPbis 将解决 400 Bad Request 的措辞,以便它也涵盖逻辑错误。所以 400 将包含 422。

来自https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-p2-semantics-18#section-7.4.1
“由于客户端错误(例如, 格式错误的语法)"

于 2012-10-15T08:21:32.000 回答
2

尽管我也一直使用 400 来表示逻辑错误,但我不得不说在这种情况下返回 400 是错误的,因为规范读取的方式。这就是我这么认为的原因,逻辑错误可能是与另一个实体的关系失败或不满意,并且对另一个实体进行更改可能会导致相同的确切结果稍后通过。就像在该员工不存在时尝试(完全假设)将员工添加为部门成员(逻辑错误)。将员工添加为成员请求可能会失败,因为员工不存在。但是,在将员工添加到系统后,同样的请求可能会通过。

只是我的 2 美分……这些天我们需要律师和法官来解释 RFC 中的语言:)

谢谢你,维什

于 2011-01-24T19:16:44.120 回答
2

有人可能会争辩说,您的请求中包含不正确的数据语法错误,即使您在 HTTP 级别(请求行、标头等)的实际请求在语法上是有效的。

例如,如果一个 Restful Web 服务被记录为接受自定义 XML 内容类型application/vnd.example.com.widget+xml为以预期的形式。

不过,我不知道有任何官方引用来支持这一点,像往常一样,它似乎归结为解释 RFC 2616。

更新:请注意RFC 7231 §6.5.1中的修订措辞:

400 (Bad Request) 状态码表示服务器不能或不会处理请求,因为某些东西被认为是客户端错误,例如格式错误的请求语法、无效的请求消息帧或欺骗性请求路由)。

似乎比现在已经过时的RFC 2616 §10.4.1更支持这个论点,它只是说:

由于语法错误,服务器无法理解该请求。客户端不应该在没有修改的情况下重复请求。

于 2011-01-24T18:31:11.943 回答
1

在 Java EE 服务器上,如果您的 URL 引用了不存在的“web 应用程序”,则会返回 400。那是“语法错误”吗?取决于语法错误的含义。我会说是的。

在英语中,句法规则规定了词类之间的某些关系。例如,“Bob marries Mary”在语法上是正确的,因为它遵循模式 {Noun + Verb + Noun}。而“鲍勃婚姻玛丽”在语法上是不正确的,{名词+名词+名词}。

简单 URL 的语法是 { protocol + : + // + server + : + port }。根据这个“ http://www.google.com:80 ”在语法上是正确的。

但是“abc://www.google.com:80”呢?它似乎遵循完全相同的模式。但实际上这是一个语法错误。为什么?因为 'abc' 不是 DEFINED 协议。

关键是确定我们是否有 400 的情况需要的不仅仅是解析字符、空格和分隔符。它还必须识别什么是有效的“词性”。

于 2013-08-29T20:42:47.040 回答
1

这是困难的。

我认为我们应该;

  1. 仅当客户端有权更改请求、标头或正文时才返回 4xx 错误,这将导致请求以相同的意图成功。

  2. 当预期的突变没有发生时返回错误范围代码,即 DELETE 没有发生或 PUT 没有改变任何东西。但是,POST 更有趣,因为规范说它应该用于在新位置创建资源,或者只处理有效负载。

使用 Vish 回答中的示例,如果请求打算将员工 Priya 添加到部门 Marketing 但未找到 Priya 或她的帐户已存档,那么这是一个应用程序错误。

该请求运行良好,它符合您的应用程序规则,客户端正确执行所有操作,ETags 匹配等等等。

因为我们使用的是 HTTP,所以我们必须根据请求对资源状态的影响做出响应。这取决于您的 API 设计。

也许你设计了这个。

PUT { updated members list } /marketing/members

返回成功代码将表明资源的“替换”有效;对资源的 GET 将反映您的更改,但不会。

所以现在你必须选择一个合适的否定 HTTP 代码,这是棘手的部分,因为这些代码主要用于 HTTP 协议,而不是你的应用程序。

当我阅读官方的 HTTP 代码时,这两个看起来很合适。

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

500(内部服务器错误)状态代码表示服务器遇到了阻止它完成请求的意外情况。

尽管我们传统上认为 500 就像一个未处理的异常:-/

我不认为发明自己的状态码是不合理的,只要它始终如一地应用和设计。

这种设计更容易处理。

PUT { membership add command } /accounts/groups/memberships/instructions/1739119

然后,您可以设计您的 API 以始终成功创建指令,它返回201 CreatedLocation标头,指令的任何问题都保留在该新资源中。

POST 更像是最后一次 PUT 到新位置。POST 允许对消息进行任何类型的服务器处理,这会打开类似“操作成功失败”之类的设计。

可能您已经编写了一个执行此操作的 API,即网站。您发布了付款表格,但由于信用卡号码错误,它被成功拒绝。

对于 POST,是否返回 200 或 201 以及拒绝消息取决于是否创建了新资源并且是否可以在其他位置获取 GET。

综上所述,我倾向于设计需要更少 PUT 的 API,也许只是更新数据字段,以及调用规则和处理的操作和内容,或者只是有更高的预期失败机会,可以设计为 POST 指令形式。

于 2019-01-23T12:45:39.213 回答
0

就我而言:

我收到 400 个错误请求,因为我设置content-type错误。我更改了内容类型,然后能够成功获得响应。

之前(问题):

ClientResponse response = Client.create().resource(requestUrl).queryParam("noOfDates", String.valueOf(limit))
                .header(SecurityConstants.AUTHORIZATION, formatedToken).
header("Content-Type", "\"application/json\"").get(ClientResponse.class);

之后(固定):

ClientResponse response = Client.create().resource(requestUrl).queryParam("noOfDates", String.valueOf(limit))
                .header(SecurityConstants.AUTHORIZATION, formatedToken).
header("Content-Type", "\"application/x-www-form-urlencoded\"").get(ClientResponse.class);
于 2020-03-05T12:42:35.233 回答