我正在构建一个允许客户端存储对象的服务器。这些对象是在客户端完全构造的,对象id在对象的整个生命周期内都是永久的。

我已经定义了API,以便客户端可以使用PUT创建或修改对象:

PUT /objects/{id} HTTP/1.1
...

{json representation of the object}

{id}是对象id,所以它是Request-URI的一部分。

现在,我也在考虑允许客户端使用POST创建对象:

POST /objects/ HTTP/1.1
...

{json representation of the object, including ID}

由于POST意味着“追加”操作,我不确定在对象已经存在的情况下该做什么。我应该把请求作为修改请求,还是应该返回一些错误代码(哪个)?


当前回答

更有可能是400个坏请求

[* * 6.5.1。400错误请求**][1]

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

由于请求包含重复的值(已经存在的值),因此可以将其视为客户机错误。需要在下次尝试之前更改请求。 通过考虑这些事实,我们可以得出HTTP STATUS 400错误请求的结论。

其他回答

用户侧故障,属于4xx组。这是正确答案https://developers.rebrandly.com/docs/403-already-exists-errors

在阅读了这篇文章和其他几篇关于状态码使用的长达数年的讨论之后,我得出的主要结论是,必须仔细阅读规范,重点关注正在使用的术语、它们的定义、关系和周围的上下文。

相反,从不同的答案中可以看出,经常发生的情况是,部分规范被剥离了上下文,并基于感觉和假设进行孤立的解释。

这将是一个相当长的回答,简短的总结是,HTTP 409是报告“添加新资源”操作失败的最合适的状态代码,如果具有相同标识符的资源已经存在。以下是对原因的解释,完全基于权威来源- RFC 7231中所述。

那么,在OP的问题中描述的情况下,为什么409冲突是最合适的状态代码?

RFC 7231对409冲突状态码的描述如下:

409(冲突)状态代码表示由于与目标资源的当前状态冲突而无法完成请求。

这里的关键组件是目标资源及其状态。

目标资源

RFC 7231对该资源的定义如下:

HTTP请求的目标称为“资源”。HTTP不限制资源的性质;它仅仅定义了一个可能用于与资源交互的接口。每个资源由统一资源标识符(Uniform resource Identifier, URI)标识,如[RFC7230]章节2.7所述。

因此,当使用HTTP接口时,我们总是通过对uri应用HTTP方法来操作由uri标识的资源。

当我们打算添加一个新资源时,基于OP的例子,我们可以:

在资源/objects/{id}中使用PUT; 对资源/对象使用POST。

/objects/{id}无关紧要,因为在使用PUT方法时不可能有冲突:

PUT方法请求用请求消息有效负载中包含的表示所定义的状态创建或替换目标资源的状态。

如果具有相同标识符的资源已经存在,它将被PUT替换。

我们将关注/objects资源和POST。

RFC 7231对POST说:

POST方法要求目标资源根据资源自己的特定语义处理请求中包含的表示。例如,POST用于以下函数(以及其他函数):…3)创建一个尚未被源服务器识别的新资源;4)将数据追加到资源的现有表示中。

与OP对POST方法的理解相反:

由于POST的意思是“追加”操作…

将数据追加到资源的现有表示只是可能的POST“函数”之一。此外,OP在提供的例子中实际上所做的不是直接将数据追加到/objects表示中,而是创建一个新的独立资源/objects/{id},然后它成为/objects表示的一部分。但这并不重要。

重要的是资源表示的概念,它把我们带到了……

资源状态

RFC 7231解释说:

考虑到资源可以是任何东西,并且HTTP提供的统一接口类似于一个窗口,通过该窗口,人们只能通过将消息传递给另一端的某个独立参与者来观察并对该事物采取行动,因此需要一个抽象来表示(“代替”)我们通信中该事物的当前或期望状态。这种抽象称为表示[REST]。

对于HTTP的目的,“表示”是旨在反映给定资源的过去、当前或期望状态的信息,其格式可以通过协议轻松通信,并由一组表示元数据和潜在的无限表示数据流组成。

这还不是全部,规范继续描述表示部分——元数据和数据,但是我们可以总结出,由元数据(报头)和数据(有效负载)组成的资源表示反映了资源的状态。

现在,我们了解了409冲突状态代码的用法所需的两个部分。

409年冲突

让我们重申:

409(冲突)状态代码表示由于与目标资源的当前状态冲突而无法完成请求。

那么它是如何合适的呢?

We POST to /objects => our target resource is /objects. OP does not describe the /objects resource, but the example looks like a common scenario where /objects is a resource collection, containing all individual "object" resources. That is, the state of the /objects resource includes the knowledge about all existing /object/{id} resources. When the /objects resource processes a POST request it has to a) create a new /object/{id} resource from the data passed in the request payload; b) modify its own state by adding the data about the newly created resource. When a resource to be created has a duplicate identifier, that is a resource with the same /object/{id} URI already exists, the /objects resource will fail to process the POST request, because its state already includes the duplicate /object/{id} URI in it.

这正是409冲突状态代码描述中提到的与目标资源当前状态的冲突。

在检查重复记录的正确代码时偶然发现了这个问题。

请原谅我的无知,但我不明白为什么每个人都忽略了代码“300”,它清楚地表示“多项选择”或“模棱两可”

在我看来,这将是构建非标准或特定系统供自己使用的完美代码。我也可能是错的!

https://www.rfc-editor.org/rfc/rfc7231#section-6.4.1

更有可能是400个坏请求

[* * 6.5.1。400错误请求**][1]

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

由于请求包含重复的值(已经存在的值),因此可以将其视为客户机错误。需要在下次尝试之前更改请求。 通过考虑这些事实,我们可以得出HTTP STATUS 400错误请求的结论。

由于您提到使用post的对象创建请求包含对象的ID,因此应该使其成为幂等请求。只返回与成功创建请求完全相同的响应。幂等请求使api更简单,例如。现在客户不必担心两种不同的情况(成功,失败)。或者客户端可以安全地重试请求,以防在连接/服务器暂时宕机时出现问题。