当前位置:  开发笔记 > 前端 > 正文

资源已存在时POST的HTTP响应代码

如何解决《资源已存在时POST的HTTP响应代码》经验,为你挑选了10个好方法。

我正在构建一个允许客户端存储对象的服务器.这些对象在客户端完全构造,完整的对象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意味着"附加"操作,我不知道如果对象已经存在该怎么做.我应该将请求视为修改请求还是应该返回一些错误代码(哪个)?



1> Wrikken..:

我的感觉是409 Conflict最合适的,然而,当然在野外很少看到:

由于与资源的当前状态冲突,无法完成请求.此代码仅在预期用户可能能够解决冲突并重新提交请求的情况下才允许.响应主体应该包含足够的信息供用户识别冲突的来源.理想情况下,响应实体将包含足够的信息供用户或用户代理解决问题; 但是,这可能是不可能的,也不是必需的.

冲突最有可能发生在响应PUT请求时.例如,如果正在使用版本控制并且包含PUT的实体更改为与早期(第三方)请求所产生的资源冲突的资源,则服务器可能会使用409响应来指示它无法完成请求.在这种情况下,响应实体可能包含由响应Content-Type定义的格式的两个版本之间的差异列表.


400 => _"由于语法格式错误,服务器无法理解请求"_.服务器完全理解,但由于冲突而无法遵守.请求和语法没有问题,只有数据问题.400会立即让我相信我使用的整个机制是有缺陷的,而不仅仅是数据.
@Wrikken那不再正确.在[RFC 7231](https://tools.ietf.org/html/rfc7231#page-58)中更改了HTTP 400,意思是"服务器不能或**不会因为某些事情而处理请求被认为是客户端错误(例如,格式错误的请求语法,无效的请求消息框架或欺骗性请求路由)."_我不是说400在这种情况下是正确的用法,但它可以用400的新定义正确.
我返回`HTTP 409`,其中`Location`标题指向现有/冲突资源.
@javajavajavajavajava:在我看来,重复的数据并不是一个"客户端错误",但这当然是旁观者的眼睛.
为什么不去400 Bad Request?对我来说,这看起来有点像验证错误(您使用非法ID提供错误的有效负载).
不是.两种定义中400的意图是告诉客户端因为请求不好而停止尝试.
@dhj可能是因为Auth0人员阅读了此页面
没有什么是“禁止的”。它们只是规格。您不必跟随他们。但是,如果您愿意,我认为422更合适。另外,303是重定向码。您没有重定向到任何东西。

2> Nullius..:

根据RFC 7231,可以使用303 See Other MAY 如果处理POST的结果等同于现有资源的表示.


这是最RESTful的答案.
对不起,我正在低估这个.HTTP 300s是关于重定向的,并且重定向到可能具有不同属性的另一个对象将是非常误导的.
我认为背景很重要.例如:返回303意味着需要重定向到找到的资源.这在服务器到服务器调用中可能有意义,但如果您正在运行用户注册过程,那么根本没有任何意义.
你不必抱歉.但是,如果表示等同于现有资源,它如何具有不同的属性?即使它有,重定向将如何误导?OP说:_我不知道如果对象已经存在该怎么办.它实际上是'相同'的对象.为什么重定向会产生误导?你在谈论另一个对象_在OP的头脑中显然不是.
在我看来,这可能是一个公认的答案.虽然"MAY"表示完全可选项,但它是官方[RFC 7231](https://tools.ietf.org/html/rfc7231#section-4.3.3)文档中建议的唯一响应代码.
只是FYI .. IE没有返回303的响应正文,如果这很重要.
@Sinaesthetic:我认为在某种情况下让客户知道'嘿,这个已经存在,你可以在这里找到它'是完全没错的.我提到的'我创建它并且它已经在这里',应该提供带有201 Created或200 Ok状态代码的Content-Location标头.因此,如果已创建某些内容,则只有200和201是有效的返回代码.这也在我在原始答案中链接的相同RFC中明确说明.我同意303在所有情况下或所有商业案例中可能都不是正确的答案.这也是他们在RFC中强调MAY的原因.

3> Gareth..:

我个人使用WebDAV扩展422 Unprocessable Entity.

根据RFC 4918

422 Unprocessable Entity状态代码装置的服务器理解的请求实体的内容类型(因此一个415 Unsupported Media Type状态码是不适当的),并且请求实体的语法是正确的(因此一个400 Bad Request状态码是不适当的),但无法处理所包含的指令.


这是一个有趣的想法,促使我最终阅读了WebDAV RFC.但是,我认为422的含义是请求和包含的实体在语法上是正确的,但在语义上没有意义.
我不会这样做.从答案中引用的相同URL:"例如,如果XML请求主体包含格式正确(即语法正确)但语义错误的XML指令,则可能会出现此错误情况." 这是一个不可处理的实体的真正含义,与您使用有效语法和语义发送完全有效的请求实体的情况不同,但唯一的问题是它与现有实体冲突.**实际上,如果请求实体的语义无效,则根本不应存在类似的现有实体.**
格式错误的JSON不是一个语法正确的实体,所以`422`让我感到奇怪......
@Tamer为什么会这样?命令"Please create object xy"在语法上是正确的.仅当可以创建对象xy时,它在语义上是正确的.如果对象xy已经存在,则无法再创建它,因此这是一个语义错误.

4> p0lar_bear..:

可能在游戏后期,但我在尝试制作REST API时偶然发现了这个语义问题.

为了扩展Wrikken的答案,我认为您可以使用409 Conflict403 Forbidden根据具体情况 - 简而言之,当用户无法解决冲突并完成请求时(例如他们无法发送请求)时,请使用403错误DELETE请求显式删除资源),或者如果可能的话可以使用409.

10.4.4 403禁止

服务器理解请求,但拒绝履行请求.授权无效,请求不应重复.如果请求方法不是HEAD并且服务器希望公开为什么请求没有得到满足,那么它应该描述实体中拒绝的原因.如果服务器不希望将此信息提供给客户端,则可以使用状态代码404(未找到).

如今,有人说"403"并且出现了权限或身份验证问题,但规范说它基本上是服务器告诉客户端它不会这样做,不要再问它,这就是为什么客户端不应该"T.

至于PUTvs. POST... POST应该用于在用户无法或不应该为资源创建标识符时创建资源的新实例.PUT在知道资源的标识时使用.

9.6 PUT

...

POST和PUT请求之间的根本区别体现在Request-URI的不同含义上.POST请求中的URI标识将处理所包含实体的资源.该资源可能是数据接受过程,某些其他协议的网关或接受注释的单独实体.相反,PUT请求中的URI标识请求附带的实体 - 用户代理知道URI的用途,并且服务器不得尝试将请求应用于其他资源.如果服务器希望将请求应用于不同的URI,

必须发送301(永久移动)响应; 然后,用户代理可以自己决定是否重定向请求.


我认为*403 Forbidden*意味着,即使用户经过*身份验证*,他也不会*授权*执行请求的操作.我不会将它用于验证错误.**示例**:未登录,我尝试删除某些内容.服务器发给我*401 Unauthorized*(这个名字很糟糕,应该是*401 Unauthenticated*).我登录后再试一次.这次服务器检查我的权限,看到我不被允许并返回*403 Forbidden*.另见[this question](http://stackoverflow.com/questions/3297048/403-forbidden-vs-401-unauthorized-http-responses).
根据规范,暗示错误409不能通过`POST`请求​​(正确使用时)返回,因为它声明它应该在与_eject resource_冲突时返回.由于目标资源尚未发布,因此无法发生冲突,因此回复"409 Conflict"没有任何意义.

5> Sławomir Len..:

这全都与上下文有关,还有谁负责在请求中重复(服务器或客户端或两者)

如果服务器仅指向重复项,请查看4xx:

400错误的请求-服务器由于明显的客户端故障而无法处理请求时

409冲突-如果服务器不处理请求,但原因不是客户端的错误

...

隐式处理重复项,请查看2XX:

200 OK

创建了201

...

如果服务器期望返回某些内容,请查看3XX:

找到302个

303查看其他

...

当服务器能够指向现有资源时,则意味着重定向。

如果上述还不够,在响应正文中准备一些错误消息始终是一个好习惯。



6> alanjds..:

"302 Found"听起来合情合理.并且RFC 2616说它可以回答除GET和HEAD之外的其他请求(这肯定包括POST)

但是它仍然让访问者通过这个URL来获取RFC的"Found"资源.为了使它直接进入真正的"找到"URL,应该使用"303 See Other",这是有道理的,但强制另一个调用GET以下的URL.好的方面,这个GET是可缓存的.

我想我会用"303见其他".我不知道我是否可以回复身体中发现的"东西",但我想这样做是为了将一次往返保存到服务器上.

更新:重新阅读RFC之后,我仍然认为不存在的 "4XX + 303 Found"代码应该是正确的.但是,"409 Conflict"是现有的最佳答案代码(由@ Wrikken指出),可能包括指向现有资源的Location头.


3xx状态用于重定向

7> Alfonso Tien..:

我认为你不应该这样做.

如您所知,POST是修改集合的,它用于创建新项目.所以,如果你发送id(我认为这不是一个好主意),你应该修改集合,即修改项目,但这是令人困惑的.

用它来添加一个没有id的项目.这是最好的做法.

如果要捕获UNIQUE约束(而不是id),则可以响应409,就像在PUT请求中一样.但不是身份证.


忘记数据库表.假设一个产品只能与一个帐户相关......那么它就是一对多的关系.所以,POST/product/{id}与{'account':account_id}.如果你将最大基数设置为'1'(一对一的关系)....为什么它们分开了休息对象?基数错误只是400错误.把事情简单化.我希望我理解你的问题.

8> Sinaesthetic..:

我认为对于REST,你只需要对该特定系统的行为做出决定,在这种情况下,我认为"正确"的答案将是这里给出的几个答案之一.如果您希望请求停止并且行为就好像客户端在继续之前犯了一个需要修复的错误,那么使用409.如果冲突真的不那么重要并且想要保持请求继续,那么通过重定向来响应客户端到找到的实体.我认为正确的REST API应该在POST之后重定向(或者至少提供位置头)到该资源的GET端点,因此这种行为将提供一致的体验.

编辑:值得注意的是,您应该考虑PUT,因为您提供了ID.然后行为很简单:"我不在乎现在有什么,把这个东西放在那里." 意思是,如果没有任何东西,它就会被创造出来; 如果有东西它会被替换.我认为当服务器管理该ID时,POST更合适.分离这两个概念基本上告诉你如何处理它(即PUT是幂等的,所以只要有效载荷有效,它总是有效,POST总是创建,所以如果有ID冲突,那么409会描述这个冲突) .



9> Grant Grycza..:

我会使用422 Unprocessable Entity,当请求无效但问题不在语法或身份验证中时使用.

作为反对其他答案的论据,使用任何非4xx错误代码意味着它不是客户端错误,显然是.使用非4xx错误代码来表示客户端错误根本没有任何意义.

这似乎409 Conflict是这里最常见的答案,但是,根据规范,这意味着资源已经存在,并且您应用于它的新数据与其当前状态不兼容.如果您要发送POST请求,例如,已经使用的用户名,则它实际上并不与目标资源冲突,因为目标资源尚未发布到.当存储的资源版本与请求的资源版本之间存在冲突时,这是一个专门用于版本控制的错误.它对于此目的非常有用,例如,当客户端缓存旧版本的资源并根据不再有条件有效的不正确版本发送请求时."在这种情况下,响应表示可能包含有助于根据修订历史合并差异的信息." 使用该用户名创建另一个用户的请求是无法处理的,与版本控制无关.

对于记录,422也是当您尝试使用已在使用的名称创建存储库时GitHub使用的状态代码.



10> Phillip Harr..:

为什么不接受202?这是一个OK请求(200s),本身没有客户端错误(400s).

来自10个状态码定义:

"202已接受.该请求已被接受处理,但处理尚未完成."

...因为它不需要完成,因为它已经存在.客户不知道它已经存在,他们没有做错任何事.

我倾向于投掷一个202,并返回类似的内容到GET /{resource}/{id}会返回的内容.


这个答案是对的.202表示服务器未发现请求有问题,但选择在响应后处理请求.这也意味着它希望处理成功.在我们的例子中,服务器知道处理将失败,因此202是错误的响应.
202的示例是队列或订阅。换句话说,如果您现在要查询请求的结果,则可能无法立即获得该结果。
推荐阅读
TXCWB_523
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有