400错误请求HTTP状态码的含义是什么?

383

我有一个JSON请求,我正在将其发布到HTTP URL。

如果requestedResource字段存在,但"Roman"是该字段的无效值,那么这应该被视为400吗?

[{requestedResource:"Roman"}] 

如果"blah"字段根本不存在,这应该被视为400吗?

[{blah:"Roman"}]

40
也许402,如果他们真的想要发送"Roman"这个值,他们只需要付更多的钱给你 :) - Jason Sperske
一个真实的场景是,我进行了PUT调用以添加一些数据。我再次使用相同的请求体进行了PUT调用,但是收到了400错误,告诉我之前的请求已经在处理中。我们的系统通常需要一些时间来添加这些数据,这是正常的。 - MasterJoe
我相信大多数人都已经注意到了,但是要明确提出来 - 这些请求应该是400响应,因为它们不是有效的JSON(我知道这不是问题的重点!) JSON需要在属性名称周围加上引号,并且不像JavaScript对象表示法那样宽容,后者不需要引号。我的主要问题答案如下。 - Jo Kemp
10个回答

394

400表示请求格式错误。换句话说,客户端发送给服务器的数据流不符合规则。

对于带有JSON有效负载的REST API,400通常会被正确地用于指示根据服务API规范,JSON以某种方式无效。

按照这种逻辑,您提供的两种情况都应该是400s。

想象一下如果这是XML而不是JSON,两种情况下,XML永远不会通过模式验证——要么是由于未定义元素,要么是由于不当的元素值。那将是一个错误的请求。这里也是同样的道理。


3
我同意你的看法,直到“按照这个逻辑,您提供的两种情况都应该是 400 错误。” 我认为 JSON 的内容在这里并不重要。当你说“格式错误”时,我认为应该解决你发送的数据格式问题,例如如果你跳过了 JSON 中的一个字段,你应该会得到 400 错误。 - Geethanga
2
在http://www.restapitutorial.com/httpstatuscodes.html上有一组不错的REST响应代码。这也可能取决于您如何处理有效请求,例如406(不可接受)或405方法不允许。然而,400是适当的,因为“由于格式不正确,服务器无法理解请求。客户端不应在未经修改的情况下重复请求。” - Andrew Scott Evans
3
“由于格式不正确,服务器无法理解请求”这个错误信息可能是由于请求本身(例如,HTTP头部格式不正确)或者请求携带的数据(例如,缺少JSON值)两种情况之一引起的。 - MC Emperor
2
Vidya说:“XML永远无法通过模式验证”。重点是XML解析器区分文档是否格式良好(即语法正确)和有效(即语义正确,例如根据模式)。 400代码的描述是“由于格式错误的语法,服务器无法理解请求”-因此不应将其用于验证错误,imho。 - Martin Lie
@Vidya,看一下这个错误:http://stackoverflow.com/questions/42851301/get-http-400-bad-request-ionic-2。我也遇到了类似的问题,请帮帮我,如果你知道的话。 - Mohan Gopi
在ASP.NET Core中,如果您收到了400错误,并且您的控制器操作方法没有明确返回该错误,那么可以安全地说该操作方法甚至没有执行的机会吗? - David Klempfner

83

来自 w3.org

10.4.1 400 错误请求

由于格式错误,服务器无法理解该请求。客户端不应在未经修改的情况下重复发送请求。


11
返回错误400的正确性不基于字段或值,而是基于整个请求。我认为HTTP 400是一个不错的选择。 - Jason Sperske
你的意思是使用400响应告诉客户端请求中的任何内容(例如URL、头部、正文等)都可能存在问题,而不仅仅是正文吗? - MasterJoe
3
对于 URL,正确的代码是 404;对于 headers,我猜这取决于具体情况。如果 headers 拒绝识别身份,则 403(禁止)似乎是正确的方式,但如果 headers 确定输出格式呢?我认为唯一合适的 400 场景是请求了一个毫无意义且不应重复的操作。我写下这个答案已经有 4 年了,现在我觉得即使出现错误,也应该返回 200,并且错误只应用于 HTTP 传输而非有效负载。 - Jason Sperske
1
这个答案已经涵盖了很多,尽管我还没有仔细阅读所有的图表 https://dev59.com/_HNA5IYBdhLWcg3wfN2O#34324179 - Jason Sperske
@JasonSperske 负载均衡器、代理和其他中间件通常使用状态码来帮助路由、报告和修复。幸运的是,像“422”这样的代码专门针对载荷,因此在规范中有一些关于载荷状态代码的空间。 - Erik Aronesty

56
选择HTTP响应代码是一项相当简单的任务,可以用简单的规则描述。唯一棘手的部分经常被遗忘的是来自RFC 7231的第6.5段:
“除非响应HEAD请求,否则服务器应发送包含错误情况说明以及它是临时条件还是永久条件的表示。”
规则如下:
  1. 如果请求成功,则返回2xx代码(重定向为3xx)。如果服务器上存在内部逻辑错误,则返回5xx。如果客户端请求有任何问题,则返回4xx代码。
  2. 查看所选类别中可用的响应代码。如果其中一个名称与您的情况匹配得很好,您可以使用它。否则,只需回退到x00代码(200、400、500)。如果您有疑问,请回退到x00代码。
  3. 在响应正文中返回错误说明。对于4xx代码,它必须包含足够的信息,以便客户端开发人员了解原因并修复客户端。由于安全原因,对于5xx,不得透露任何细节。
  4. 如果客户端需要区分不同的错误,并根据其采取不同的反应,则定义一种可读性良好和可扩展的错误格式,并在API中使用它。从一开始就这样做是一个好习惯。
  5. 请记住,客户端开发人员可能会做一些奇怪的事情,尝试解析您作为人类可读说明返回的字符串。通过更改字符串,您将破坏这样的糟糕编写的客户端。因此,始终提供机器可读的说明并尝试避免在文本中报告附加信息。
所以在您的情况下,如果用户输入中包含“Roman”且客户端必须有特定反应,则应返回400错误和以下内容:
{
    "error_type" : "unsupported_resource",
    "error_description" : "\"Roman\" is not supported"
}

或者更一般的错误,如果这种情况是客户端中的逻辑错误,并且不被期望,除非开发人员做错了什么:

{
    "error_type" : "malformed_json",
    "error_description" : "\"Roman\" is not supported for \"requestedResource\" field"
}

23
在这两种情况下,“语法不正确”都不是问题所在,而是语义有误。因此,在我看来,返回400是不合适的。相反,应该返回200,并附带一些错误对象,例如{"error": {"message": "未知请求关键字"}}或其他类似的内容。
考虑客户端处理路径。语法错误(例如无效的JSON)是程序逻辑中的错误,换句话说,是某种错误,应该相应地进行处理,类似于403;换句话说,出现了一些严重的问题。
另一方面,参数值错误是语义上的错误,可能是由于用户输入验证不当等原因。这不是HTTP错误(尽管我认为它可能是422)。处理路径将不同。
例如,在jQuery中,我更喜欢不必编写单个错误处理程序来处理500和某些特定于应用程序的语义错误。其他框架,如Ember,也将HTTP错误(如400和500)视为大失败,需要程序员检测发生了什么并根据是否是“真正”的错误进行分支。

4
+1,HTTP中的P代表协议。如果响应是HTTP错误,那么应该是一个低级别的问题。多年来,我一直在使用torazaburo描述的方法避免了很多代码复杂性。如果我们都编写具有弹性的代码而不是经常因HTTP错误而崩溃,REST领域将会减少很多痛苦。 - Dem Pilafian
27
状态码200表示请求已经被处理,所以客户端应该执行常规成功逻辑。在这里,我们明显有一个错误,因此响应不能有2xx或3xx代码。它也不能是5xx,因为那是服务器端错误,而我们的错误是在客户端发生的。因此,必须是4xx错误。但是,在响应正文中提供错误描述是正确的做法,实际上这是HTTP规范建议的一种方式。 - Alexey Guseynov
422 对于日志记录器、代理和其他工具来说更好。 - Erik Aronesty
我知道这已经过时了,但为了信息的完整性,向该特定服务器发出无效请求是不合法的。对于此情况,一个好的状态码是422,它是客户端错误,因为它在HTTP语法上是正确的,但由于它在该服务器上的请求在语义上不可处理,所以请求无法处理。虽然该状态码是为WebDAV而设计的,但其目的相同,并且在此用途中应该是有效的。您可以在此处查看完整列表:https://en.wikipedia.org/wiki/List_of_HTTP_status_codes。 - Barkermn01

19

除了表示“请求格式错误”以外,使用400状态码是错误的。

如果请求有效负载包含无法解析为application/json(如果服务器期望该数据格式)的字节序列,则应使用适当的状态码415:

服务器拒绝服务请求,因为所请求方法的请求实体需要在请求的资源上下文中使用不支持的格式。

如果请求有效负载在语法上正确但在语义上不正确,则可以使用非标准的422响应码或标准的403状态码:

服务器已理解请求,但拒绝执行。授权将无助于解决问题,不应重复该请求。


3
不,状态码415用于表示实体类型错误,例如在“Content-Type”标头中声明为“image/gif”而不是“text/json”。据推测,如果多部分消息的组件指定了错误的类型,也适用此状态码。有关更多讨论,请参阅https://tools.ietf.org/html/rfc4918,在其中讨论了状态码422。 - Jasen

10

考虑预期。

作为客户端应用程序,您希望知道服务器端是否出现错误。如果服务器需要在缺少blah或者requestedResource值不正确时抛出错误,则400错误是合适的。


我的想法完全一样。 - Captain Jack Sparrow

8

这让我想起了和别人的一个常见对话,"我理解-只是我不同意"

400表示服务器无法理解请求

200表示服务器准确理解并完全处理了请求。

当服务器返回200时,它在说:"我理解了您的请求,我已经处理完毕并没有遇到任何错误,并且这是我的正确响应"。

200意味着您可以信任响应中发送的答案。也许答案是"罗马人不允许" - 但无论如何,这都是一个适当的答案,并且没有发生任何意外的问题。

200并不表达有关预期错误或已处理的异常的任何信息 - 因为这不是消息传输过程的一部分。这些是有关HTTP的状态代码,是传输本身的状态。

我认为应该避免模糊"传输/通信"和"处理"之间的界线。

对于那些喜欢使用HTTP代码指示处理问题(“我不同意”部分)的人,似乎409冲突最适用于"不允许罗马人"
RFC 7231 409冲突

冲突几乎意味着"缺乏协议",对吗?

无论您选择哪种HTTP响应代码,似乎每个人都同意您的响应应该解释为什么失败以及如何解决它。对于罗马人来说,也许返回一个字段的可接受值列表?


7

首先检查URL是否正确,如果正确,则检查您发送的请求正文,可能的原因是您发送的请求缺少正确的语法。

具体而言,请检查请求字符串中的特殊字符。如果使用了(特殊字符),则这是此错误的根本原因。

尝试复制请求并分析每个标记的数据。


我遇到了http 400错误,检查后发现我的请求中有一些特殊字符。为了解决这个问题,我在内容类型中传递了charset=UTF-8。 - Kislay Kishore

6
作为一个补充,对于那些可能会遇到与我相同问题的人,我正在使用$.ajax将表单数据发送到服务器,并且一开始也遇到了400错误。
假设我有一个JavaScript变量,
var formData = {
    "name":"Gearon",
    "hobby":"Be different"
    }; 

不要直接使用变量formData作为键data的值,如下所示:

$.ajax({
    type: "post",
    dataType: "json",
    url: "http://localhost/user/add",
    contentType: "application/json",
    data: formData,
    success: function(data, textStatus){
        alert("Data: " + data + "\nStatus: " + status); 
    }
});

不要这样使用,而是按照以下方式使用JSON.stringify来封装formData

$.ajax({
    type: "post",
    dataType: "json",
    url: "http://localhost/user/add",
    contentType: "application/json",
    data: JSON.stringify(formData),
    success: function(data, textStatus){
        alert("Data: " + data + "\nStatus: " + status); 
    }
});

无论如何,正如其他人所说明的那样,错误是因为服务器无法识别请求导致语法错误,我只是在实践中举了一个例子。希望对某个人有所帮助。


我认为 OP 是在询问当请求没有格式错误,但某种方式不符合应用程序级别要求时,是否应该返回 400 作为适当的错误代码。例如,您可以创建一个在线计算器,将方程式作为 JSON 发送。如果您发送有效的添加数字和字符串的 json,则请求是正确的,但从应用程序语义上讲是不正确的。但是,您的浏览器会将此请求视为“错误的”。 - Jeppe

0
在我的情况下,这意味着我提供的 JSON 数据与数据库所需的数据不兼容。例如,电子邮件地址已添加到数据库中,然后它会抛出 400 错误代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接