POST请求引用未知实体,400与422响应的区别

9
我正在尝试确定在“类似REST”API上不同场景下应该返回什么正确的状态码。
以下示例源自关于语法类型问题,但是我的问题假设整个过程中都有有效的语法。
假如我有一个端点允许以JSON格式POST购买内容。它看起来像这样:
{
    "account_number": 45645511,
    "upc": "00490000486",
    "price": 1.00,
    "tax": 0.08
}

如果:

  • 账号不存在
  • 账号已关闭或
  • 识别的账号不是正确类型的账号

这些都是阻止“处理”发生的业务层问题,其中一个场景涉及到在GET中可能是404的内容。

请注意,账号号码不在URL中,因此404是否具有误导性?

合适的状态码是什么?

1
这些答案中有没有对你有用的? - Peter Bratton
可能是400与422响应POST数据的重复问题 - gdvalderrama
不是的。这是关于业务层问题,而不是语法(视图层)问题。 - Simon Gibbs
5个回答

18

让我们逐个来看这些代码。每个代码都是向客户端发出的信号,表示服务器正常运行,但在成功执行请求之前必须更改某些内容。

400(错误请求)状态码表示由于客户端错误(例如,格式错误的请求语法、无效的请求消息框架或欺骗性请求路由),服务器无法或不会处理请求。

400通常表示语法错误;作为用户,应该在再次尝试之前检查请求的结构

服务器未找到与请求URI匹配的任何内容。没有给出条件是暂时还是永久的指示。如果服务器通过一些内部可配置的机制知道旧资源永久不可用并且没有转发地址,则应使用410(已删除)状态码。当服务器不希望透露拒绝请求的确切原因或没有其他响应适用时,通常使用此状态代码。

404是web服务器无法将url路径与任何内容匹配时使用的标准代码。作为客户端,应该在再次尝试之前检查请求的URL

422(无法处理的实体)状态码表示服务器理解请求实体的内容类型(因此415(不支持的媒体类型)状态码不合适),并且请求实体的语法正确(因此400(错误请求)状态码不合适),但无法处理包含的指令。例如,如果XML请求正文包含形式良好(即、语法上正确的)但语义上有误的XML指令,则可能会发生此错误条件。

422通常用于内容违规。作为用户,应该在再次尝试之前检查请求的内容

现在针对你的情况,账户号码是标识号码,但未包含在URL中。404将向用户发出信号,表明URL错误,而不是有效负载。换句话说,假设您的URL为:

http://www.myservice.net/endpoint

一个404错误提示对我来说意味着在/endpoint上没有服务存在,而不是没有账号。无论我提交什么内容,服务器都不会处理我的请求。那么我应该进行的修复是查找URL中的错误,而不是数据有效负载。所以对我来说,422会指引我朝着正确的方向前进,除非你开始在URL中包含账号。

最终,这些都是设计偏好,只要确保您将它们清楚地传达给您的用户即可。


最终我们选择了409,因为我们的场景反映出资源状态(由URL标识)与客户端期望的状态之间存在冲突。这里的“状态”指的是某些松散相关实体的状态。 - Simon Gibbs
1
422表示客户端不应重复请求而不进行修改。然而,在OP提到的所有三种情况中,可能会执行某些外部操作,使请求有效(例如,帐户已创建、重新打开或授予正确权限),这将使客户端能够使用相同的数据重复请求。因此,我认为409更合适。 - andre_ss6

2
如果您认为账户是资源状态的一部分(虽然间接),那么您可能也会考虑使用409,因为该状态与请求的语义存在冲突。
然而,在Ruby on Rails和Dropwizard中,422越来越受欢迎,它用于指示身体部位的非语法问题。这种增长趋势向使用API的开发人员发出了一个强烈的信号,告诉他们需要排除语法并关注身体。开发人员时间通常是客户所承担的最大成本,因此通过引导他们的开发人员的注意力,您将使他们感到满意。
因此,409是可能的答案,尽管相对较新颖,而422则是更传统的方法,尽管RoR和DropWizard显然都比较新,因此这些惯例可以说正在迅速改变!

2
我曾在不同场合使用过这两种方法。409 还有一个好处,它是原始的 RFC 2616 HTTP 规范的一部分。但趋势似乎是使用 WebDAV 的 422 代码。 - Peter Bratton

1
我认为在您的情况下422是足够的,但如果与您的API的其余部分一致,则400也不错。当客户端出现问题时,使用400作为错误代码是一个常见的惯例,但要么该错误不符合特定的错误代码,要么您不想使用太多错误代码。
如果POST负载存在问题,则404绝对是错误的。

-2

情况1:账号不存在。 这是404的标准情况。

情况2:账号已关闭。 这与逻辑有关,如果您在关闭账号时保留了账号详细信息,则可以给出404。如果您在关闭账号后不保留账号详细信息,则必须标记它(如提高某些标志)(或任何您拥有的逻辑)。在这种情况下,状态码400和适当的失败原因以及可能的纠正措施即可。

情况3:识别的账号不是正确类型的账号。 对我来说,403是有意义的,因为该账号未被授权完成任何购买。如果没有授权账号的概念,则400并附带解释性消息即可。但在这种情况下,我会坚持使用403。


如果账号编号不在URL中或者UPC未知,该怎么办? - Simon Gibbs
我强烈建议不要在URL中包含账号。如果必须这样做,请进行编码以确保安全性。尽量像问题中所示,在请求正文中传递此信息。如果请求正文中没有账号,您的服务器应该抛出一个错误请求(400),告诉客户端未收到预期的媒体类型。为了更通用,您必须在进一步处理之前尽可能验证JSON。验证将涵盖UPC未知于系统的部分,对象未找到(404)应该是有效的状态代码。 - abj1305
1
被踩了。 “这是404的标准情况。”显然不正确,因为标准情况是URL旨在识别缺失的资源。该情况在问题中并不普遍。 - Simon Gibbs

-3

实际上,在这种情况下,404 对我来说听起来不错。


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