问题 REST中的PUT与POST
根据HTTP / 1.1规范:
该 POST
method用于请求源服务器接受请求中包含的实体作为由该标识所标识的资源的新下级 Request-URI
在里面 Request-Line
换一种说法, POST
习惯了 创建。
该 PUT
方法请求将所包含的实体存储在提供的实体下 Request-URI
。如果 Request-URI
指的是已经存在的资源,封闭的实体应该被认为是驻留在源服务器上的实体的修改版本。如果 Request-URI
没有指向现有资源,并且该URI能够被请求用户代理定义为新资源,源服务器可以使用该URI创建资源。
那是, PUT
习惯了 创建或更新。
那么,应该使用哪一个来创建资源?或者需要支持两者?
12544
2018-03-10 14:25
起源
答案:
总体:
PUT和POST都可以用于创建。
你必须问“你在做什么动作?”区分你应该使用什么。我们假设您正在设计一个用于提问的API。如果您想使用POST,那么您可以将其添加到问题列表中。如果你想使用PUT,你会对特定问题这样做。
两者都可以使用,所以我应该在我的RESTful设计中使用哪一个:
您不需要同时支持PUT和POST。
使用哪种方法取决于你。但请记住使用正确的,具体取决于您在请求中引用的对象。
一些考虑:
- 您是否明确指定了您创建的URL对象,还是让服务器决定?如果您为它们命名,那么使用PUT。如果您让服务器决定然后使用POST。
- PUT是幂等的,所以如果你将对象PUT两次,它就没有效果。这是一个很好的属性,所以我会尽可能使用PUT。
- 您可以使用具有相同对象URL的PUT更新或创建资源
- 使用POST,您可以同时有2个请求进行URL修改,并且可以更新对象的不同部分。
一个例子:
我写了以下内容作为SO的另一个答案的一部分:
POST:
用于修改和更新资源
POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/
请注意以下是一个错误:
POST /questions/<new_question> HTTP/1.1
Host: www.example.com/
如果尚未创建URL,则表示您
不应该使用POST来创建它
同时指定名称。这应该
导致“找不到资源”错误
因为 <new_question>
不存在
然而。你应该把它 <new_question>
首先是服务器上的资源。
你可以这样做
这个用POST创建资源:
POST /questions HTTP/1.1
Host: www.example.com/
请注意,在这种情况下资源
未指定name,新对象
URL路径将返回给您。
放:
用于创建资源,或
覆盖它。当你指定
资源新网址。
对于新资源:
PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/
要覆盖现有资源:
PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/
3487
2018-03-10 14:29
你可以在网上找到断言
两者都不对。
更好的是在PUT和POST之间进行选择 幂等 行动。
放 意味着放置一个资源 - 用不同的东西完全替换给定URL上的任何可用资源。根据定义,PUT是幂等的。你喜欢这么多次,结果是一样的。 x=5
是幂等的。无论以前是否存在,您都可以投入资源(例如,创建或更新)!
POST 更新资源,添加辅助资源或导致更改。 POST的方式不是幂等的 x++
不是幂等的。
通过这个论点,PUT用于在您知道要创建的事物的URL时创建。当您知道要创建的事物类别的“工厂”或管理员的URL时,可以使用POST创建。
所以:
POST /expense-report
要么:
PUT /expense-report/10929
1882
2018-04-22 14:55
- POST 到URL 创建子资源 在... 服务器定义 URL。
- 放 到URL 创建/替换资源 完整的 客户定义 URL。
- 补丁 到URL 更新 部分 资源 在该客户端定义的URL。
PUT和POST的相关规范是 RFC2616§9.5ff。
POST创建子资源,所以POST到 /items
创造一种生活在世界之下的资源 /items
资源。
例如。 /items/1
。两次发送相同的post数据包将创建两个资源。
放 用于创建或替换资源 客户端已知的URL。
因此: 放 只是CREATE的候选者,客户端在创建资源之前已经知道了url。例如。 /blogs/nigel/entry/when_to_use_post_vs_put
因为标题用作资源键
放 如果已存在,则替换已知URL上的资源,因此两次发送相同的请求无效。换一种说法, 对PUT的调用是幂等的。
RFC读起来像这样:
POST和PUT请求之间的根本区别体现在Request-URI的不同含义上。 POST请求中的URI标识将处理所包含实体的资源。该资源可能是数据接受过程,某些其他协议的网关或接受注释的单独实体。相反,PUT请求中的URI标识请求附带的实体 - 用户代理知道URI的用途,并且服务器不得尝试将请求应用于其他资源。如果服务器希望将请求应用于不同的URI,
注意: PUT主要用于更新资源(通过全部替换它们),但最近有使用PATCH更新现有资源的动作,因为PUT指定它替换整个资源。 RFC 5789。
563
2018-04-07 05:52
概要:
创建:
可以通过以下方式使用PUT或POST执行:
放
创建 THE 新资源 newResourceId 作为标识符,在/ resources URI下,或 采集。
PUT /resources/<newResourceId> HTTP/1.1
POST
创建 一个 / resources URI下的新资源,或 采集。通常,服务器返回标识符。
POST /resources HTTP/1.1
更新:
能够 只要 以下列方式使用PUT执行:
放
使用更新资源 existingResourceId 作为标识符,在/ resources URI下,或 采集。
PUT /resources/<existingResourceId> HTTP/1.1
说明:
在处理REST和URI时,你有 通用 在...上 剩下 和 具体 在...上 对。该 仿制药 通常被称为 集合 而且更多 具体 可以调用项目 资源。注意一个 资源 可以包含一个 采集。
例子:
< - generic - specific - >
URI: website.com/users/john
website.com - whole site
users - collection of users
john - item of the collection, or a resource
URI:website.com/users/john/posts/23
website.com - whole site
users - collection of users
john - item of the collection, or a resource
posts - collection of posts from john
23 - post from john with identifier 23, also a resource
当你使用POST时,你是 总是 参考a 采集所以每当你说:
POST /users HTTP/1.1
你正在发布一个新用户 用户 采集。
如果你继续尝试这样的事情:
POST /users/john HTTP/1.1
它会工作,但在语义上你说你想要添加资源 约翰 采集 在下面 用户 采集。
一旦你使用PUT,你就是指的是 资源 或单个项目,可能在一个 采集。所以当你说:
PUT /users/john HTTP/1.1
你告诉服务器更新,或创建它是否不存在, 约翰 资源 在下面 用户 采集。
规格:
让我重点介绍一下规范的一些重要部分:
POST
该 POST 方法用于请求原始服务器 接受 请求中包含的实体为 新 下属 请求行中的Request-URI标识的资源
因此,创造一个新的 资源 在...上 采集。
放
该 放 方法请求封闭的实体 存储 在提供的Request-URI下。如果Request-URI引用了 已经存在 资源,封闭的实体应该被视为一个 修改版 驻留在原始服务器上的那个。如果Request-URI有 没有指向现有的 资源,那个URI是 能 被定义为 新 资源 通过请求用户代理,源服务器可以 创建 具有该URI的资源。“
因此,基于存在而创建或更新 资源。
参考:
164
2017-08-14 22:47
我想补充一下我的“务实”建议。当您知道可以检索要保存的对象的“id”时,请使用PUT。如果您需要返回数据库生成的ID以供将来查找或更新,则使用PUT将无法正常工作。
因此:要保存现有用户,或者客户端生成ID的用户,并且已验证该ID是唯一的:
PUT /user/12345 HTTP/1.1 <-- create the user providing the id 12345
Host: mydomain.com
GET /user/12345 HTTP/1.1 <-- return that user
Host: mydomain.com
否则,使用POST初始创建对象,并使用PUT更新对象:
POST /user HTTP/1.1 <--- create the user, server returns 12345
Host: mydomain.com
PUT /user/12345 HTTP/1.1 <--- update the user
Host: mydomain.com
155
2018-01-15 19:59
POST表示“创建新”,如“以下是创建用户的输入,为我创建”。
PUT表示“插入,替换,如果已经存在”,如“这是用户5的数据”。
您发布到example.com/users,因为您还不知道用户的URL,您希望服务器创建它。
您将pUT发送到example.com/users/id,因为您要替换/创建一个 具体 用户。
使用相同数据发布两次意味着创建两个具有不同ID的相同用户。使用相同数据进行两次输入会使用户创建第一次并在第二次将其更新为相同状态(无更改)。因为你在PUT之后无论你执行它多少次都会得到相同的状态,所以每次都被称为“同样有效” - 幂等。这对于自动重试请求很有用。当您按下浏览器上的后退按钮时,不再“您确定要重新发送”吗?
一般建议是在需要服务器控制资源的URL生成时使用POST。否则使用PUT。首选PUT over POST。
144
2017-10-23 14:27
使用POST创建,并使用PUT进行更新。无论如何,Ruby on Rails就是这样做的。
PUT /items/1 #=> update
POST /items #=> create
104
2018-03-10 14:28
REST是一个 非常 高层次的概念。事实上,它甚至根本没有提到HTTP!
如果您对如何在HTTP中实现REST有任何疑问,您可以随时查看 原子发布协议(AtomPub) 规范。 AtomPub是一个使用HTTP编写RESTful webservices的标准,由许多HTTP和REST杰出人员开发,其中一些来自REST的发明者和HTTP本身(共同)发明者Roy Fielding的输入。
实际上,您甚至可以直接使用AtomPub。虽然它来自博客社区,但它绝不仅限于博客:它是一种通用协议,用于通过HTTP与任意资源的任意(嵌套)集合进行REST交互。如果您可以将应用程序表示为嵌套的资源集合,那么您可以使用AtomPub而不用担心是使用PUT还是POST,要返回的HTTP状态代码以及所有这些详细信息。
这就是AtomPub关于资源创建的说法(第9.2节):
要将成员添加到集合,客户端会将POST请求发送到集合的URI。
57
2018-03-10 15:27
是否使用PUT或POST在具有HTTP + REST API的服务器上创建资源的决定取决于谁拥有URL结构。 让客户端知道或参与定义URL结构是一种不必要的耦合,类似于SOA产生的不良耦合。逃避类型的耦合是REST如此受欢迎的原因。因此, 正确使用的方法是POST。 此规则有例外情况,当客户希望保留对其部署的资源的位置结构的控制时,就会出现这种情况。这很少见,可能意味着其他问题。
在这一点上,有些人会争辩说,如果 REST风格的URL的 如果使用,客户端确实知道资源的URL,因此PUT是可接受的。毕竟,这就是为什么规范,规范化,Ruby on Rails,Django URL很重要,看看Twitter API ......等等等等。那些人需要了解 没有Restful-URL这样的东西 然后 罗伊菲尔丁自己说:
REST API不能定义固定资源名称或层次结构(an
客户端和服务器的明显耦合)。服务器必须具有自由
控制自己的命名空间。相反,允许服务器指示
客户端如何构造适当的URI,例如在HTML中完成
表单和URI模板,通过在媒体中定义这些指令
类型和链接关系。 [失败在这里意味着客户是
假设由于带外信息而产生资源结构,例如
特定于域的标准,它是面向数据的等价物
RPC的功能耦合]。
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
一个想法 REST风格的URL 实际上是违反REST,因为服务器负责URL结构,应该可以自由决定如何使用它来避免耦合。如果这让您感到困惑,请阅读有关API设计中自我发现的重要性。
使用POST创建资源需要考虑设计因素,因为POST不是幂等的。 这意味着多次重复POST并不能保证每次都有相同的行为。 这会让人们在不应该使用PUT时创建资源。 他们知道这是错误的(POST是为了CREATE),但无论如何他们都这样做,因为他们不知道如何解决这个问题。在以下情况中证明了这种担忧:
- 客户端将新资源POST到服务器。
- 服务器处理请求并发送响应。
- 客户端永远不会收到响应。
- 服务器不知道客户端没有收到响应。
- 客户端没有资源的URL(因此PUT不是一个选项)并重复POST。
- POST不是幂等的,服务器......
第6步是人们常常对做什么感到困惑。但是,没有理由创建解决此问题的方法。相反,可以按照指定使用HTTP RFC 2616 并且服务器回复:
10.4.10 409冲突
由于与当前的冲突,请求无法完成
资源状态。此代码仅在以下情况下允许
预计用户可能能够解决冲突
重新提交请求。响应机构应该包含足够的内容
用户识别冲突根源的信息。
理想情况下,响应实体将包含足够的信息
用户或用户代理来解决问题;然而,这可能不是
可能而且不是必需的。
冲突最有可能发生在响应PUT请求时。对于
如果正在使用版本控制并且实体是PUT
包括对资源的更改与资产的更改
在早期(第三方)请求中,服务器可能会使用409响应
表示无法完成请求。在这种情况下,
响应实体可能包含两者之间的差异列表
这两个版本采用响应Content-Type定义的格式。
回复状态代码为409 Conflict是正确的追索权,因为:
- 执行具有与系统中已有资源匹配的ID的数据POST是“与资源的当前状态冲突”。
- 由于重要的部分是让客户了解服务器有资源并采取适当的措施。这是“用户可能能够解决冲突并重新提交请求的情况”。
- 包含具有冲突ID的资源的URL以及资源的适当前提条件的响应将为用户或用户代理提供“足以解决问题的信息”,这是每个RFC 2616的理想情况。
基于RFC 7231的发布更新为替换2616
RFC 7231 旨在取代2616和in 第4.3.3节 描述了POST的可能响应
如果处理POST的结果等于a
现有资源的表示,原始服务器可以重定向
通过发送303(请参阅其他)响应来访问该资源的用户代理
使用“位置”字段中的现有资源标识符。这个
具有为用户代理提供资源标识符的好处
并通过更适合的方法转移表示
共享缓存,但是以用户的额外请求为代价
代理程序尚未缓存表示形式。
现在可能很想在POST重复的情况下简单地返回303。然而,事实恰恰相反。只有多个创建请求(创建不同的资源)返回相同的内容时,返回303才有意义。一个例子是“感谢您提交请求消息”,客户端每次都不需要重新下载。 RFC 7231仍然在4.2.2节中保持POST不是幂等的,并继续保持POST应该用于创建。
有关此内容的更多信息,请阅读此内容 文章。
53
2017-10-29 23:00
我喜欢这个建议 RFC 2616对PUT的定义:
POST和PUT请求之间的根本区别体现在Request-URI的不同含义上。 POST请求中的URI标识将处理所包含实体的资源。该资源可能是数据接受过程,某些其他协议的网关或接受注释的单独实体。相反,PUT请求中的URI标识请求附带的实体 - 用户代理知道URI的用途,并且服务器不得尝试将请求应用于其他资源。
这与其他建议相吻合,PUT最适用于已有名称的资源,POST适用于在现有资源下创建新对象(并让服务器为其命名)。
我解释这个,以及对PUT的幂等性要求,意味着:
- POST适用于在集合下创建新对象(并且创建不需要是幂等的)
- PUT适用于更新现有对象(并且更新需要是幂等的)
- POST也可用于对现有对象的非幂等更新(特别是,在不指定整个对象的情况下更改对象的一部分 - 如果您考虑它,创建集合的新成员实际上是这种类型的特殊情况从集合的角度更新)
- 当且仅当您允许客户端命名资源时,PUT也可用于创建。但是,由于REST客户端不应该对URL结构做出假设,因此这不符合预期的精神。
48
2018-01-11 17:18