首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如果资源不存在,HTTP PUT是否应该创建资源?

如果资源不存在,HTTP PUT是否应该创建资源?
EN

Stack Overflow用户
提问于 2019-05-21 22:30:15
回答 3查看 19K关注 0票数 22

假设有人在我的endoint上执行PUT请求:

代码语言:javascript
运行
复制
/resources/{id}

但是,在我的PostgreSQL数据库中没有存储具有给定id的资源。

根据RFC 2616,如果我能够:

PUT方法请求将封闭的实体存储在提供的Request-URI下。如果请求URI引用已存在的资源,则应将包含的实体视为驻留在源服务器上的实体的修改版本。如果请求URI不指向现有资源,并且该URI能够被请求用户代理定义为新资源,则源服务器可以使用该URI创建资源。

是否可以使用提供的id创建资源?因为在数据库插入时手动分配ids不是最佳实践。

如果无法创建资源,我是否应该返回404错误?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-05-21 22:55:15

首先,您使用的是一个过时的文档:RFC2616如今已不再适用,任何使用此类文档作为参考的人都应该立即停止使用。

引用Mark Nottingham的话,他在撰写本文时是IETF HTTP和QUIC工作组的联合主席:

请勿使用RFC2616。从你的硬盘驱动器,书签中删除它,并刻录(或负责任地回收)任何打印出来的副本。

旧的RFC 2616已被以下文档取代,这些文档共同定义了HTTP/1.1协议:

如果您正在寻找方法、状态代码和标头定义,那么RFC 7231是您应该参考的文档。

话虽如此,让我们回到你的问题上。

如果资源不存在,

PUT是否应该创建资源?

那得看情况。

但是,如果您的应用程序代表客户端生成资源标识符,那么您应该使用POST而不是PUT来创建资源。

下面引用了PUT方法定义的某些部分。最后一句话似乎与你最相关(亮点是我的),支持我刚才提到的:

PUT方法请求创建目标资源的状态,或者用请求消息有效负载中封装的表示定义的状态替换目标资源的状态。..。

如果目标资源没有当前表示,并且PUT成功地创建了一个表示,则源服务器必须通过发送201 (Created)响应来通知用户代理。如果目标资源确实具有当前表示,并且根据所附表示的状态成功地修改了该表示,则源服务器必须发送200 (OK)或204 (No Content)响应,以指示请求成功完成。..。

PUT请求的正确解释假定用户代理知道需要哪个目标资源。在接收到状态更改请求后,代表客户端选择适当URI的服务应该使用POST PUT**.**方法而不是方法来实现 ...

如果无法创建资源,是否应该返回404错误?

这似乎是要返回的准确状态代码,因为没有找到所请求资源的表示形式:

404 (Not Found)状态代码表示源服务器没有找到目标资源的当前表示,或者不愿意公开存在该表示。..。

现在,为了完整起见,在下面的POST方法定义中找到一些相关的引号,这些引号应该用于在您的问题中描述的场景中创建资源:

POST方法请求目标资源根据资源自身的特定语义处理请求中包含的表示。例如,POST用于以下函数(以及其他函数):

..。

  • 创建源站尚未标识的新资源;

..。

如果作为成功处理POST请求的结果而在源服务器上创建了一个或多个资源,则源服务器应发送201 ( created )响应,其中包含Location报头字段,该字段提供所创建的主资源的标识符,以及在引用新资源时描述请求状态的表示。

201状态代码指示已创建新资源,而Location标头指示新创建的资源所在的位置。如果未提供Location标头,则客户端应假定资源是由有效的请求URI标识的:

201 ( created )状态代码指示请求已完成,并导致创建了一个或多个新资源。由请求创建的主资源由响应中的Location标头字段标识,或者,如果没有接收到Location字段,则由有效的请求URI标识。...

票数 45
EN

Stack Overflow用户

发布于 2019-05-21 23:32:15

简而言之,这取决于您想要存储的有效负载是否违反了服务器对资源的任何约束。

一般而言,我认为它应该尝试这样做,因为客户端显式地表达了将该特定表示存储在目标URI中的意图。但是,服务器应该在此之前执行约束检查!通常,在真正的REST场景中,客户端应该使用服务器提供的URI,而不是自己选择任何URI。因此,服务器应该控制其名称空间,因此默认情况下不建议使用PUT创建资源。

话虽如此,由于PUT是幂等的,而POST不是,所以一些客户可能想要从这个属性中受益。在这里,POST-PUT creation pattern已经发展,客户端尝试通过POST创建新资源,直到它通过响应中的Location头接收到确认,然后尝试通过PUT更新该资源的状态。这样,客户端可以确保在传输问题的情况下,表示只创建了一次。根据不同的立场,有些人可能会将资源的实际更新视为实际的资源创建,尽管由于客户端预先收到了相应的链接,但情况并非如此。

请注意,如果服务器被配置为为某些URI端点提供特定的表示,则服务器也有权将表示转换为不同的内容。设想通过PUT将图像上传到URI,然后服务器将图像嵌入到HTML页面

票数 2
EN

Stack Overflow用户

发布于 2021-11-16 21:41:42

这里嵌入了两个问题: 1)应该尝试创建资源,2)如果不能,会发生什么。

1) @cass链接的RFC表示https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4

PUT方法请求创建目标资源的状态,或者用请求消息有效负载中包含的表示定义的状态替换目标资源的状态。给定表示的成功PUT将意味着在相同目标资源上的后续GET将导致在200 (OK)响应中发送等效的表示。

此外,Mozilla的文本https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT

HTTP PUT请求方法创建一个新资源,或者用请求有效负载替换目标资源的表示。

此外,从原始的RFC (被上面的测试替换) https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

PUT方法请求将封闭的实体存储在提供的Request-URI下。如果请求URI引用已存在的资源,则应将包含的实体视为驻留在源服务器上的实体的修改版本。如果请求URI不指向现有资源,并且该URI能够被请求用户代理定义为新资源,则源服务器可以使用该URI创建资源。

这有点轶事,但Kubernetes API也小心地进行了这种区分,并通知它的修补程序的用户,如果他们真的意味着更新:https://kubernetes.io/docs/reference/using-api/api-concepts/#api-verbs

对于PUT请求,Kubernetes根据现有对象的状态在内部将其分类为create或update。更新不同于补丁;补丁的HTTP动词是补丁。

2在“如果失败会发生什么”方面,我认为代码取决于出错的地方:

  • 400:由于负载错误而无法创建
  • 409:由于冲突而无法创建-例如,输入JSON中的某些字段对其进行了某些全局唯一性检查
  • 502/3-无法创建,因为它尝试调用数据库,但它已死

我不确定404是不是最好的代码,因为它没有告诉用户任何原因。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56240547

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档