让我们假设有人对我的内标执行PUT
请求:
/resources/{id}
但是我的PostgreSQL数据库中没有存储具有给定ID的资源。
根据RFC 2616,如果有能力,我应该创建资源:
PUT
方法请求将包含的实体存储在提供的Request-URI下。如果Request-URI引用了已经存在的资源,则应将封闭的实体视为驻留在原始服务器上的实体的修改版本。如果Request-URI没有指向现有资源,并且请求用户代理能够将该URI定义为新资源,则原始服务器可以使用该URI创建资源。
可以使用提供的ID创建资源吗?最好不要在数据库插入上手动分配ID。
如果无法创建资源,是否应该返回404
错误?
答案 0 :(得分:4)
首先,您正在使用过时的文档:RFC 2616如今已不再适用,使用此类文档作为参考的任何人都应立即停止。
引用Mark Nottingham,在撰写本文时,他是IETF HTTP和QUIC工作组的共同主席:
请勿使用RFC2616 。从硬盘驱动器,书签中将其删除,并刻录(或负责地回收)打印出的所有副本。
以下定义了HTTP / 1.1协议的文档已取代了旧的RFC 2616:
如果要查找方法,状态代码和标题定义,那么RFC 7231是您应参考的文档。
话虽如此,让我们回到您的问题。
如果不存在,HTTP
PUT
应该创建一个资源吗?
要视情况而定。
但是,如果您的应用程序代表客户端生成资源标识符,如您在问题中提到的,则应使用POST
而不是PUT
来创建资源。
下面引用了PUT
方法定义的某些部分。最后一句话似乎与您最相关(重点是我的),支持我上面刚刚提到的内容:
PUT
方法请求创建目标资源的状态或将其替换为请求消息有效负载中包含的表示形式所定义的状态。 [...]如果目标资源没有当前表示形式,并且
PUT
成功创建了一个表示形式,则原始服务器务必通过发送201
(已创建)响应来通知用户代理。如果目标资源确实具有当前表示形式,并且该表示形式已根据所包含表示形式的状态被成功修改,则原始服务器务必发送200
(确定)或204
(否内容)响应,表明请求已成功完成。 [...]对
PUT
请求的正确解释假定用户代理知道需要哪个目标资源。 代表客户端选择适当URI的服务,在收到状态更改请求后,应使用POST
方法而非PUT
来实现。 [。 。]
如果无法创建资源,是否应该返回
404
错误?
这似乎是要返回的准确状态代码,因为未找到所请求资源的表示形式:
404
(未找到)状态码表示原始服务器未找到目标资源的当前表示或不愿意透露该资源的存在。 [...]
为了完整起见,现在在POST
方法定义下找到一些相关的引号,这些引号应用于在问题所描述的场景中创建资源:
POST
方法请求目标资源根据资源自身的特定语义来处理请求中包含的表示形式。例如,POST
用于以下功能(以及其他功能):[...]
- 创建尚未由原始服务器识别的新资源;
[...]
如果由于成功处理
POST
请求而在原始服务器上创建了一个或多个资源,则原始服务器应发送包含{{1}的201
(已创建)响应}标头字段,它为创建的主要资源提供标识符,并提供一种描述,同时引用新资源时描述请求的状态。
尽管201
状态码指示已创建新资源,而Location
标头指示新创建的资源位于何处。如果没有提供Location
标头,则客户端应假定资源由有效请求URI标识:
Location
(已创建)状态码表示请求已得到满足,并导致创建了一个或多个新资源。由请求创建的主要资源由响应中的201
头字段标识,或者,如果未收到Location
字段,则由有效请求URI标识。 [...]
答案 1 :(得分:1)
简而言之,这取决于您要存储的有效负载是否违反服务器对资源的任何限制。
通常,我会说它应该尝试执行此操作,因为客户端明确表达了将特定表示存储在目标URI中的意图。服务器应该在执行约束检查之前!通常,尽管如此,在真实的REST场景中,客户端应使用服务器提供的URI,而不仅仅是自己选择任何URI。因此,服务器应控制其名称空间,因此默认情况下,建议不要使用PUT
创建资源。
话虽这么说,由于PUT
是等幂的,而POST
不是幂等的,因此某些客户可能希望从此属性中受益。 POST-PUT creation pattern在这里得到了发展,客户端尝试通过POST
创建新资源,直到客户端通过响应中的Location
标头收到确认,然后尝试更新该资源的通过PUT
状态。这样,客户端可以确保在传输问题的情况下表示仅创建一次。视情况而定,有些人可能会将资源的实际更新视为实际的资源创建,尽管由于客户端已预先获得相应的链接,所以情况并非如此。
请注意,如果服务器被配置为为某些URI端点提供特定的表示形式,则服务器也有权将表示形式转换为其他形式。考虑通过PUT将图像上传到URI,然后服务器将图像嵌入HTML页面