我正在构建一个允许客户端存储对象的服务器 . 这些对象在客户端完全构造,完整的对象ID对于对象的整个生命周期是永久的 .
我已经定义了API,以便客户端可以使用PUT创建或修改对象:
PUT /objects/{id} HTTP/1.1
...
{json representation of the object}
是对象ID,因此它是Request-URI的一部分 .
现在,我也在考虑允许客户端使用POST创建对象:
POST /objects/ HTTP/1.1
...
{json representation of the object, including ID}
由于POST意味着“追加”操作,我不知道如果对象已经存在该怎么办 . 我应该将请求视为修改请求还是应该返回一些错误代码(哪个)?
15 回答
208 - http://httpstatusdogs.com/208-already-reported怎么样?这是一个选择吗?
在我看来,如果唯一的东西是重复资源,则不应该引发错误 . 毕竟,客户端或服务器端都没有错误 .
另一种可能的治疗方法是使用PATCH . PATCH定义为改变内部状态的东西,不限于追加 .
PATCH允许您更新现有项目,从而解决问题 . 见:RFC 5789: PATCH
在检查重复记录的正确代码时偶然发现了这个问题 .
请原谅我的无知,但我不明白为什么每个人都忽略了代码“300”,它清楚地说“多选”或“暧昧”
在我看来,这将是构建非标准或特定系统供您自己使用的完美代码 . 我也错了!
https://tools.ietf.org/html/rfc7231#section-6.4.1
返回418怎么样?
因为客户端要求保留已经存在于服务器上的实体,服务器最终会生气并认为他是一个茶壶并返回:
418 I'm a teapot
.参考文献:
RFC 2324
Practical usage
Blog explaining the code
SO question
我的感觉是
409 Conflict
是最合适的,然而,当然在野外很少见到:可能在游戏后期,但我在尝试制作REST API时偶然发现了这个语义问题 .
为了扩展Wrikken的答案,我认为你可以使用
409 Conflict
或403 Forbidden
,具体取决于具体情况 - 简而言之,当用户无法解决冲突并完成请求时,使用403错误(例如,他们不能发送DELETE
请求以显式删除资源),或者如果可能的话可以使用409 .如今,有人说“403”和权限或身份验证问题浮现在脑海中,但规范说它基本上是服务器告诉客户端它不会这样做,不要再问它,这就是为什么客户端不应该“T .
至于
PUT
与POST
...POST
应该用于在用户无法或不应该为资源创建标识符时创建资源的新实例 . 资源的标识已知时使用PUT
.我认为对于REST,你只需要对该特定系统的行为做出决定,在这种情况下,我认为“正确”的答案将是这里给出的几个答案之一 . 如果您希望请求停止并且行为就好像客户端在继续之前犯了一个需要修复的错误,那么使用409.如果冲突真的不那么重要并且想要保持请求继续,那么通过重定向来响应客户端到找到的实体 . 我认为正确的REST API应该在POST之后重定向(或至少提供位置头)到该资源的GET endpoints ,因此这种行为将提供一致的体验 .
编辑:值得注意的是,你应该考虑一个PUT,因为你提供了ID . 然后行为很简单:“我现在不关心那里有什么,把这件事放在那里 . ”意思是,如果没有任何东西,它就会被创造出来;如果有东西它会被替换 . 我认为POST是当服务器管理该ID时更合适 . 分离这两个概念基本上告诉你如何处理它(即PUT是幂等的,所以只要有效载荷有效,它总是有效,POST总是创建,所以如果有ID冲突,那么409会描述这个冲突) .
这都是关于 context ,还有谁负责重复(服务器或客户端或两者)
如果服务器只是 point the duplicate ,请查看4xx:
400 Bad Request - 当服务器不处理请求时,因为它显然是客户端故障
409冲突 - 如果服务器不处理请求,但原因不是客户端的错误
对于 implicit 处理重复项,请查看2XX:
200好的
201创建
如果服务器是 expected to return something ,请查看3XX:
发现
302
303见其他
当服务器能够指向现有资源时,意味着重定向 .
如果以上是不够的,那么在响应主体中准备一些错误消息总是一个好习惯 .
为什么不 202 Accepted ?这是一个OK请求(200s),本身没有客户端错误(400s) .
来自10 Status Code Definitions:
...因为它不需要完成,因为它已经存在 . 客户不知道它已经存在,他们没有做错任何事 .
我倾向于投掷一个202,并返回类似的内容到GET
/{resource}/{id}
将返回的内容 ."302 Found"听起来合情合理 . 并且RFC 2616表示可以回答除GET和HEAD之外的其他请求(这肯定包括POST)
但它仍然让访问者通过这个URL来获取RFC的“Found”资源 . 为了使它直接进入真正的“找到”URL,应该使用“303 See Other”,这是有道理的,但强制另一个调用GET以下的URL . 好的方面,这个GET是可缓存的 .
我认为 I would use "303 See Other" . 我不知道我是否可以回复身体中的"thing",但我想这样做是为了将一次往返保存到服务器 .
UPDATE: 重新阅读RFC后,我仍然认为 inexistent "4XX+303 Found"代码应该是正确的 . 但是, "409 Conflict" is the best existing answer code (由@ Wrikken指出),可能包括指向现有资源的Location头 .
我认为你不应该这样做 .
如您所知,POST是修改集合的,它用于创建新项目 . 所以,如果你发送id(我认为这不是一个好主意),你应该修改集合,即修改项目,但这是令人困惑的 .
用它来添加一个没有id的项目 . 这是最好的做法 .
如果要捕获UNIQUE约束(而不是id),则可以响应409,就像在PUT请求中一样 . 但不是身份证 .
更有可能是
400 Bad Request
由于请求包含重复值(已存在的值),因此可将其视为客户端错误 . 需要在下次尝试之前更改请求 .
通过考虑这些事实,我们可以得出结论为HTTP STATUS 400 Bad Request .
我个人使用WebDAV扩展
422 Unprocessable Entity
.REST Patterns describes it as
我会使用
422 Unprocessable Entity
,当请求无效但问题不在语法或身份验证中时使用 .作为反对其他答案的论据,使用任何非
4xx
错误代码意味着它不是客户端错误,显然是 . 使用非4xx
错误代码来表示客户端错误根本没有任何意义 .似乎
409 Conflict
是这里最常见的答案,但是,根据规范,这意味着资源已经存在,并且您应用于它的新数据与其当前状态不兼容 . 如果您要发送POST
请求,例如,已使用的用户名,则当存储的资源版本与请求的资源版本之间存在冲突时,'s not actually conflicting with the target resource, as the target resource has not yet been posted to. It'是专门针对版本控制的错误 . 它对于此目的非常有用,例如,当客户端缓存旧版本的资源并根据不再有条件有效的不正确版本发送请求时 . "In this case, the response representation would likely contain information useful for merging the differences based on the revision history."使用该用户名创建另一个用户的请求是无法处理的,与版本控制无关 .对于记录,422也是当您尝试使用已在使用的名称创建存储库时GitHub使用的状态代码 .
根据RFC 7231,可以使用 303 See Other 如果处理POST的结果等同于现有资源的表示 .