5922

根据RFC 2616, § 9.5POST用于创建资源:

POST 方法用于请求源服务器接受请求中包含的实体,作为 Request-Line 中 Request-URI 标识的资源的新下级。

根据RFC 2616,第 9.6 节PUT用于创建或替换资源:

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

那么应该使用哪种 HTTP 方法来创建资源呢?还是应该同时支持?

4

38 回答 38

4626

总体:

PUT 和 POST 都可用于创建。

你必须问,“你在做什么?”,以区分你应该使用什么。假设您正在设计一个用于提问的 API。如果您想使用 POST,那么您可以对问题列表执行此操作。如果您想使用 PUT,那么您将对特定问题执行此操作。

太好了,两者都可以使用,所以我应该在我的 RESTful 设计中使用哪一个:

您不需要同时支持 PUT 和 POST。

您使用哪个取决于您。但是请记住根据您在请求中引用的对象来使用正确的对象。

一些考虑:

  • 您是明确命名您创建的 URL 对象,还是让服务器决定?如果您命名它们,则使用 PUT。如果您让服务器决定然后使用 POST。
  • PUT 被定义为假定幂等性,所以如果你 PUT 一个对象两次,它应该没有额外的效果。这是一个不错的属性,所以我会尽可能使用 PUT。只需确保 PUT 幂等性实际上在服务器中正确实现。
  • 您可以使用具有相同对象 URL 的 PUT 更新或创建资源
  • 使用 POST,您可以同时收到 2 个请求来修改 URL,它们可能会更新对象的不同部分。

一个例子:

我写了以下内容作为关于此问题的另一个答案的一部分:

邮政:

用于修改和更新资源

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/

请注意,在这种情况下,未指定资源名称,新的对象 URL 路径将返回给您。

放:

用于创建资源或覆盖它。在您指定资源的新 URL 时。

对于新资源:

PUT /questions/<new_question> HTTP/1.1
Host: www.example.com/

要覆盖现有资源:

PUT /questions/<existing_question> HTTP/1.1
Host: www.example.com/

此外,更简洁一点的是,RFC 7231 第 4.3.4 节 PUT状态(强调添加),

4.3.4. 放

PUT 方法请求目标资源的状态是 createdreplaced具有由请求消息有效负载中包含的表示定义的状态。

于 2009-03-10T14:29:46.930 回答
2392

你可以在网上找到断言说

两者都不完全正确。


更好的是根据动作的幂等性在 PUT 和 POST 之间进行选择。

PUT意味着放置一个资源——用不同的东西完全替换给定 URL 上可用的任何东西。根据定义,PUT 是幂等的。你喜欢做多少次,结果都是一样的。x=5是幂等的。您可以放置​​一个资源,无论它以前是否存在(例如,创建或更新)!

POST更新资源、添加辅助资源或导致更改。POST 不是幂等的,以非幂等的方式x++


通过这个论点,PUT 用于在您知道要创建的事物的 URL 时进行创建。当您知道要创建的事物类别的“工厂”或经理的 URL 时,可以使用 POST 来创建。

所以:

POST /expense-report

或者:

PUT  /expense-report/10929
于 2010-04-22T14:55:54.930 回答
784
  • POST到 URL在服务器定义的 URL 处创建子资源
  • PUT to a URL在客户端定义的 URL 处创建/替换整个资源
  • 对 URL的PATCH会更新该客户端定义的 URL 处的部分资源。

PUT 和 POST 的相关规范是RFC 2616 §9.5ff。

POST 创建一个子资源,因此 POST/items创建一个位于该资源下的/items资源。例如。/items/1. 两次发送相同的 post 数据包将创建两个资源。

PUT用于在客户端已知的 URL上创建或替换资源。

因此:PUT只是 CREATE 的候选者,其中客户端在创建资源之前已经知道 url。例如。/blogs/nigel/entry/when_to_use_post_vs_put因为标题被用作资源键

如果已知 url 处的资源已经存在,则PUT会替换该资源,因此两次发送相同的请求无效。换句话说,对 PUT 的调用是幂等的

RFC 是这样写的:

POST 和 PUT 请求的根本区别体现在 Request-URI 的不同含义上。POST 请求中的 URI 标识将处理封闭实体的资源。该资源可能是一个数据接受进程,一个通往其他协议的网关,或者一个接受注释的单独实体。相比之下,PUT 请求中的 URI 标识了请求中包含的实体——用户代理知道 URI 的意图,服务器不得尝试将请求应用于其他资源。如果服务器希望将请求应用于不同的 URI,

注意: PUT 主要用于更新资源(通过整体替换它们),但最近出现了使用 PATCH 更新现有资源的趋势,因为 PUT 指定它替换整个资源。RFC 5789。

2018 年更新:有一种情况可以避免 PUT。请参阅“没有 PUT 的 REST”

使用“没有 PUT 的 REST”技术,其想法是强制消费者发布新的“统一”请求资源。如前所述,更改客户的邮寄地址是对新“ChangeOfAddress”资源的 POST,而不是具有不同邮寄地址字段值的“客户”资源的 PUT。

取自REST API 设计 - Thoughtworks 的 Prakash Subramaniam 的资源建模

这迫使 API 避免多个客户端更新单个资源的状态转换问题,并与事件溯源和 CQRS 更好地匹配。当工作异步完成时,发布转换并等待它被应用似乎是合适的。

于 2010-04-07T05:52:52.900 回答
291

POST表示“创建新”,如“这是创建用户的输入,为我创建”。

PUT表示“插入,如果已存在则替换”,如“这是用户 5 的数据”。

POST访问 example.com/users,因为您还不知道URL用户的身份,您希望服务器创建它。

PUT可以访问 example.com/users/id,因为您想替换/创建特定用户。

使用相同的数据发布两次意味着创建两个具有不同 ID 的相同用户。使用相同的数据进行两次 PUT 会创建第一个用户,第二次将他更新到相同的状态(无更改)。PUT由于无论执行多少次都会以相同的状态结束,因此可以说每次都“同等有效” - 幂等。这对于自动重试请求很有用。当您按下浏览器上的后退按钮时,不再有“您确定要重新发送”。

一般建议是POST在您需要服务器控制URL资源生成时使用。PUT否则使用。更 喜欢PUT .POST

于 2011-10-23T14:27:31.723 回答
260

概括:

创造:

可以通过以下方式使用 PUT 或 POST 执行:

/resources URI 或collection下以newResourceId作为标识符创建新资源。

PUT /resources/<newResourceId> HTTP/1.1 

邮政

在 /resources URI 或collection下创建一个新资源。通常标识符由服务器返回。

POST /resources HTTP/1.1

更新:

只能通过以下方式使用 PUT 执行

在 /resources URI 或collection下以existingResourceId作为标识符更新资源。

PUT /resources/<existingResourceId> HTTP/1.1

解释:

当一般处理 REST 和 URI时,左边是通用的,右边特定的。泛型通常称为集合,更具体的项目可以称为资源。请注意,资源可以包含一个集合

例子:

<-- 通用 -- 具体 -->

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 时,你总是在引用一个集合,所以每当你说:

POST /users HTTP/1.1

您正在向users 集合发布新用户。

如果你继续尝试这样的事情:

POST /users/john HTTP/1.1

它会起作用,但是从语义上讲,您是说要在users集合下的john 集合中添加资源。

使用 PUT 后,您指的是资源或单个项目,可能在集合中。所以当你说:

PUT /users/john HTTP/1.1

您正在告诉服务器更新,或者如果它不存在,则创建users集合下的john 资源

规格:

让我强调一下规范的一些重要部分:

邮政

POST方法用于请求源服务器接受请求中包含的实体,作为Request-Line 中 Request-URI 标识的资源的下级

因此,在集合上创建一个新资源

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

因此,根据资源的存在创建或更新。

参考:

于 2013-08-14T22:47:18.633 回答
182

我想补充一下我的“务实”建议。当您知道可以检索所保存对象的“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
于 2011-01-15T19:59:06.533 回答
159

两者都用于客户端到服务器之间的数据传输,但它们之间存在细微差别,分别是:

邮政
替换现有资源或在资源不存在时创建。 www.example.com/com/customer/{customerId} www.example.com/com/customer/123/order/{orderId}标识符由客户端选择。 创建新资源和从属资源,例如,文件从属于包含它的目录,或者行从属于数据库表。www.example.com/com/customer/ www.example.com/com/customer/123/order/标识符由服务器返回
幂等,即如果你PUT的资源两次,它没有效果。示例:尽可能多地做它,结果将是相同的。x=1; POST既不安全也不幂等。例子:x++;
具体工作 作为抽象的作品
如果您使用创建或更新资源PUT然后再次进行相同的调用,则该资源仍然存在并且仍然具有与第一次调用相同的状态。 发出两个相同POST的请求很可能会导致两个资源包含相同的信息。

比喻:

  • PUT 即取原处。
  • POST 作为在邮局发送邮件。

在此处输入图像描述

社交媒体/网络类比:

  • 在社交媒体上发布:当我们发布消息时,它会创建新帖子。
  • 为我们已经发布的消息放置(即编辑)。
于 2015-09-11T13:12:44.277 回答
144

使用 POST 创建,使用 PUT 更新。无论如何,Ruby on Rails 就是这样做的。

PUT    /items/1      #=> update
POST   /items        #=> create
于 2009-03-10T14:28:57.680 回答
74

REST 是一个非常高级的概念。事实上,它甚至根本没有提到 HTTP!

如果您对如何在 HTTP 中实现 REST 有任何疑问,可以随时查看Atom 发布协议 (AtomPub)规范。AtomPub 是一种使用 HTTP 编写 RESTful Web 服务的标准,由许多 HTTP 和 REST 杰出人士开发,其中一些输入来自 REST 的发明者和 HTTP 本人的(共同)发明者 Roy Fielding。

事实上,您甚至可以直接使用 AtomPub。虽然它来自博客社区,但绝不限于博客:它是一种通用协议,用于通过 HTTP 与任意(嵌套)任意资源集合进行 RESTful 交互。如果您可以将您的应用程序表示为资源的嵌套集合,那么您可以只使用 AtomPub 而不必担心是使用 PUT 还是 POST、返回什么 HTTP 状态代码以及所有这些细节。

这就是 AtomPub 对资源创建的看法(第 9.2 节):

要将成员添加到集合中,客户端将 POST 请求发送到集合的 URI。

于 2009-03-10T15:27:52.047 回答
69

使用 PUT 还是 POST 在具有 HTTP + REST API 的服务器上创建资源的决定取决于谁拥有 URL 结构。让客户端知道或参与定义 URL 结构是一种不必要的耦合,类似于 SOA 产生的不希望的耦合。转义类型的耦合是 REST 如此受欢迎的原因。因此,正确使用的方法是 POST。此规则也有例外,当客户希望保留对其部署的资源的位置结构的控制权时,就会出现例外情况。这种情况很少见,很可能意味着有其他问题。

此时有些人会争辩说,如果使用RESTful-URL,客户端确实知道资源的 URL,因此 PUT 是可以接受的。毕竟,这就是为什么规范化、规范化、Ruby on Rails、Django URL 很重要的原因,看看 Twitter API……等等等等。这些人需要明白,没有 Restful-URL 这样的东西,而且Roy Fielding 自己说

REST API 不得定义固定的资源名称或层次结构(客户端和服务器的明显耦合)。服务器必须可以自由控制自己的命名空间。相反,允许服务器通过在媒体类型和链接关系中定义这些指令来指导客户端如何构建适当的 URI,例如在 HTML 表单和 URI 模板中完成。[这里的失败意味着客户端由于带外信息而假设资源结构,例如特定于域的标准,它是面向数据的等价于 RPC 的功能耦合]。

http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

RESTful-URL的想法实际上违反了 REST,因为服务器负责 URL 结构,应该可以自由决定如何使用它以避免耦合。如果这让您感到困惑,请阅读关于 API 设计中自我发现的重要性。

使用 POST 创建资源需要考虑设计,因为 POST 不是幂等的。这意味着多次重复 POST 并不能保证每次都具有相同的行为。这会吓到人们在不应该使用 PUT 来创建资源时使用。他们知道这是错误的(POST 用于 CREATE),但他们还是这样做了,因为他们不知道如何解决这个问题。这种担忧体现在以下情况:

  1. 客户端向服务器发布一个新资源。
  2. 服务器处理请求并发送响应。
  3. 客户端永远不会收到响应。
  4. 服务器不知道客户端没有收到响应。
  5. 客户端没有资源的 URL(因此 PUT 不是一个选项)并重复 POST。
  6. POST 不是幂等的,服务器……</li>

第 6 步是人们通常对要做什么感到困惑的地方。但是,没有理由创建一个组合来解决这个问题。相反,可以按照RFC 2616中的规定使用 HTTP,服务器回复:

10.4.10 409 冲突

由于与资源的当前状态冲突,无法完成请求。仅在预期用户可能能够解决冲突并重新提交请求的情况下才允许使用此代码。响应正文应该包含足够的

供用户识别冲突来源的信息。理想情况下,响应实体将包含足够的信息供用户或用户代理解决问题;但是,这可能是不可能的,也不是必需的。

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

回复状态码 409 Conflict 是正确的方法,因为

  • 对 ID 与系统中已有资源匹配的数据执行 POST 是“与资源的当前状态发生冲突”。</li>
  • 因为重要的部分是让客户端了解服务器拥有资源并采取适当的行动。这是“预期用户可能能够解决冲突并重新提交请求的情况”。</li>
  • 包含具有冲突 ID 的资源的 URL 和资源的适当先决条件的响应将为“用户或用户代理解决问题提供足够的信息”,这是 RFC 2616 的理想情况。

基于 RFC 7231 发布的更新以替换 2616

RFC 7231旨在取代 2616,并在第 4.3.3 节中描述了以下可能的 POST 响应

如果处理 POST 的结果等同于现有资源的表示,则源服务器可以通过在 Location 字段中发送带有现有资源标识符的 303(参见其他)响应来将用户代理重定向到该资源。这样做的好处是为用户代理提供资源标识符并通过更适合共享缓存的方法传输表示,但如果用户代理尚未缓存表示,则会以额外请求为代价。

如果重复 POST,现在可能很想简单地返回 303。然而,事实恰恰相反。仅当多个创建请求(创建不同的资源)返回相同的内容时,返回 303 才有意义。一个例子是客户端不需要每次都重新下载的“感谢您提交请求消息”。RFC 7231 在第 4.2.2 节中仍然坚持 POST 不是幂等的,并继续坚持应该使用 POST 进行创建。

有关这方面的更多信息,请阅读这篇文章

于 2013-10-29T23:00:55.573 回答
55

我喜欢这个建议,来自RFC 2616 对 PUT 的定义

POST 和 PUT 请求的根本区别体现在 Request-URI 的不同含义上。POST 请求中的 URI 标识将处理封闭实体的资源。该资源可能是一个数据接受进程,一个通往其他协议的网关,或者一个接受注释的单独实体。相比之下,PUT 请求中的 URI 标识了请求中包含的实体——用户代理知道 URI 的意图,服务器不得尝试将请求应用于其他资源。

这与此处的其他建议相吻合,即 PUT 最好应用于已经有名称的资源,而 POST 适合在现有资源下创建新对象(并让服务器为其命名)。

我将这一点以及 PUT 的幂等性要求解释为:

  • POST 适合在集合下创建新对象(并且 create 不需要是幂等的)
  • PUT 有利于更新现有对象(并且更新需要是幂等的)
  • POST 也可用于对现有对象的非幂等更新(尤其是在不指定整个对象的情况下更改对象的一部分——如果您考虑一下,创建集合的新成员实际上是这种类型的特例更新,从集合的角度来看)
  • 当且仅当您允许客户端命名资源时,PUT 也可用于创建。但是,由于 REST 客户端不应该对 URL 结构做出假设,因此这不符合预期的精神。
于 2012-01-11T17:18:54.103 回答
53

简而言之:

PUT是幂等的,如果执行一次或多次相同的操作,则资源状态将相同。

POST是非幂等的,与执行一次相比,如果多次执行操作,资源状态可能会变得不同。

类比数据库查询

PUT可以想到类似“UPDATE STUDENT SET address = "abc" where id="123";

POST你可以想像 "INSERT INTO STUDENT(name, address) VALUES ("abc", "xyzzz");

学生 ID 是自动生成的。

使用 PUT,如果多次或一次执行相同的查询,则 STUDENT 表状态保持不变。

在 POST 的情况下,如果多次执行相同的查询,则会在数据库中创建多个学生记录,并且每次执行“INSERT”查询时数据库状态都会更改。

注意: PUT 需要一个需要更新的资源位置(已经资源),而 POST 不需要。因此,直观上 POST 是为了创建新资源,而 PUT 是为了更新已经存在的资源。

有些人可能会提出可以使用 POST 执行更新。没有硬性规定哪一个用于更新或哪一个用于创建。这些都是惯例,直觉上我倾向于上述推理并遵循它。

于 2016-07-29T11:11:21.423 回答
47

POST 就像将一封信发送到邮箱或将电子邮件发送到电子邮件队列。PUT 就像你把一个物体放在一个小房间或架子上的一个地方(它有一个已知的地址)。

使用 POST,您将发布到 QUEUE 或 COLLECTION 的地址。使用 PUT,您将放入 ITEM 的地址。

PUT 是幂等的。您可以发送请求 100 次,这无关紧要。POST 不是幂等的。如果您发送请求 100 次,您将在邮箱中收到 100 封电子邮件或 100 封信件。

一般规则:如果您知道项目的 id 或名称,请使用 PUT。如果您希望接收方分配项目的 id 或名称,请使用 POST。

POST 与 PUT

于 2013-06-14T18:10:25.177 回答
45

简短的回答:

简单的经验法则:使用 POST 创建,使用 PUT 更新。

长答案:

邮政:

  • POST 用于向服务器发送数据。
  • 当资源的 URL 未知时很有用

放:

  • PUT 用于将状态传输到服务器
  • 当资源的 URL 已知时很有用

更长的答案:

要理解它,我们需要质疑为什么需要 PUT,PUT 试图解决 POST 无法解决的问题是什么。

从 REST 架构的角度来看,这并不重要。我们也可以没有 PUT。但从客户开发人员的角度来看,这让他/她的生活变得简单多了。

在 PUT 之前,客户端无法直接知道服务器生成的 URL,或者它是否已经生成了任何 URL,或者要发送到服务器的数据是否已经更新。PUT 让开发人员摆脱了所有这些头疼的问题。PUT 是幂等的,PUT 处理竞争条件,PUT 让客户端选择 URL。

于 2017-10-15T02:33:32.157 回答
44

新答案(现在我更了解 REST):

PUT 只是对从现在开始服务应该使用什么内容来呈现客户端标识的资源的表示的声明;POST 是关于从现在开始服务应该包含哪些内容(可能是重复的)的声明,但如何识别该内容取决于服务器。

PUT x(如果x标识资源):“用x我的内容替换由标识的资源的内容。”

PUT x(如果x没有识别资源):“创建一个包含我的内容的新资源并用于x识别它。”

POST x:“存储我的内容并给我一个标识符,我可以使用该标识符来标识包含所述内容(可能与其他内容混合)的资源(旧的或新的)。所述资源应该与所x标识的资源相同或从属。” “ y的资源从属于x的资源”通常但不一定通过使y成为x的子路径(例如x =/fooy = /foo/bar)并修改x资源的表示以反映存在的方式来实现新资源,例如带有指向y的超链接的资源和一些元数据。只有后者对于良好的设计才是真正必不可少的,因为 URL 在 REST 中是不透明的——无论如何,您应该使用超媒体而不是客户端 URL 构造来遍历服务。

在 REST 中,不存在包含“内容”的资源。我将服务用于一致呈现表示的数据称为“内容”。它通常由数据库或文件(例如图像文件)中的一些相关行组成。由服务将用户的内容转换为服务可以使用的内容,例如将 JSON 有效负载转换为 SQL 语句。

原始答案(可能更容易阅读)

PUT /something(如果/something已经存在):“拿走你所拥有的/something,用我给你的来代替。”

PUT /something(如果/something不存在的话):“拿走我给你的东西,放在/something.”

POST /something:“把我给你的东西拿来放在你想要的任何地方/something,只要你完成后给我它的 URL。”

于 2012-08-01T20:10:42.607 回答
39

Ruby on Rails 4.0 将使用“PATCH”方法而不是 PUT 来进行部分更新。

RFC 5789 提到了 PATCH(自 1995 年以来):

需要一种新方法来提高互操作性并防止错误。PUT 方法已经定义为用一个完整的新主体覆盖资源,并且不能重用以进行部分更改。否则,代理和缓存,甚至客户端和服务器,可能会对操作的结果感到困惑。POST 已经被使用,但没有广泛的互操作性(例如,没有标准的方法来发现补丁格式支持)。PATCH 在早期的 HTTP 规范中提到过,但没有完全定义。

Edge Rails:PATCH 是用于更新的新的主要 HTTP 方法”解释它。

于 2012-02-26T09:21:30.570 回答
30

冒着重申已经说过的话的风险,记住PUT意味着客户端在创建资源时控制URL最终将成为什么似乎很重要。因此,在PUTPOST之间进行选择的一部分将是关于您可以信任客户端提供与您的 URL 方案是什么一致的正确、规范化的URL的程度。

当您不能完全信任客户端做正确的事情时,使用POST创建一个新项目,然后在响应中将 URL 发送回客户端会更合适。

于 2011-03-25T10:17:54.237 回答
29

除了其他人提出的差异之外,我想再添加一个。

POST方法中,您可以发送正文参数form-data

PUT方法中,您必须发送正文参数x-www-form-urlencoded

标题Content-Type:application/x-www-form-urlencoded

据此,您不能在PUT方法中发送文件或多部分数据

编辑

内容类型“application/x-www-form-urlencoded”对于发送大量二进制数据或包含非 ASCII 字符的文本效率低下。内容类型“multipart/form-data”应用于提交包含文件、非 ASCII 数据和二进制数据的表单。

这意味着如果您必须提交

文件、非 ASCII 数据和二进制数据

你应该使用POST方法

于 2018-09-25T08:28:16.707 回答
28

以一种非常简单的方式,我以 Facebook 时间线为例。

案例 1:当您在时间轴上发布某些内容时,这是一个全新的条目。所以在这种情况下,他们使用 POST 方法,因为 POST 方法是非幂等的。

案例 2:如果您的朋友第一次对您的帖子发表评论,那也会在数据库中创建一个新条目,因此使用 POST 方法。

案例 3:如果您的朋友编辑了他的评论,在这种情况下,他们有一个评论 ID,因此他们将更新现有评论,而不是在数据库中创建新条目。因此,对于这种类型的操作,请使用 PUT 方法,因为它是幂等的。*

在一行中,使用POST在数据库中添加新条目,并使用PUT更新数据库中的某些内容。

于 2017-02-14T06:55:05.080 回答
25

最重要的考虑是可靠性。如果 POST 消息丢失,则系统状态未定义。自动恢复是不可能的。对于 PUT 消息,仅在第一次成功重试之前状态未定义。

例如,使用 POST 创建信用卡交易可能不是一个好主意。

如果您的资源碰巧有自动生成的 URI,您仍然可以通过将生成的 URI(指向空资源)传递给客户端来使用 PUT。

其他一些考虑:

  • POST 使整个包含资源的缓存副本无效(更好的一致性)
  • PUT 响应不可缓存,而 POST 响应可缓存(需要 Content-Location 和过期)
  • PUT 较少受到 Java ME、旧浏览器、防火墙等的支持
于 2012-02-08T16:31:54.340 回答
19

刚接触这个主题的读者会被关于你该做什么的无休止的讨论以及相对缺乏经验教训所震惊。我认为 REST 优于 SOAP 的事实是从经验中学习的高级别的,但是我们一定是从那里取得进步的吧?现在是 2016 年。Roy 的论文是在 2000 年。我们开发了什么?它有趣吗?容易集成吗?支持?它会处理智能手机的兴起和不稳定的移动连接吗?

根据 ME 的说法,现实生活中的网络是不可靠的。请求超时。连接被重置。网络一次中断数小时或数天。火车与移动用户一起进入隧道。对于任何给定的请求(正如在所有讨论中偶尔承认的那样),请求可能在途中落入水中,或者响应可能在返回途中落入水中。在这种情况下,直接针对实质性资源发出 PUT、POST 和 DELETE 请求总是让我觉得有点野蛮和幼稚。

HTTP 没有做任何事情来确保请求-响应的可靠完成,这很好,因为这正是网络感知应用程序的工作。开发这样的应用程序,您可以跳过箍以使用 PUT 而不是 POST,然后如果检测到重复请求,则更多箍在服务器上给出某种错误。回到客户端,您必须跳过障碍来解释这些错误、重新获取、重新验证和重新发布。

或者您可以这样做:将您的不安全请求视为短暂的单用户资源(我们称它们为操作)。客户端通过对资源的空 POST 请求对实质性资源执行新的“操作”。POST 将仅用于此目的。一旦安全地拥有新生成的操作的 URI,客户端会将不安全的请求发送到操作 URI,而不是目标资源。解决操作和更新“真实”资源是您的 API 的正确工作,并且在这里与不可靠的网络分离。

服务器执行业务,返回响应并将其存储在约定的操作 URI中。如果出现任何问题,客户端会重复请求(自然行为!),如果服务器已经看到它,它会重复存储的响应并且不执行任何其他操作

您将很快发现与 promise 的相似之处:我们在执行任何操作之前创建并返回结果的占位符。也像一个承诺,一个动作可以成功或失败一次,但它的结果可以重复获取。

最重要的是,我们为发送和接收应用程序提供了将唯一标识的操作与各自环境中的唯一性相关联的机会。我们可以开始要求并强制执行!客户负责任的行为:尽可能多地重复您的请求,但在您拥有现有请求的明确结果之前不要生成新的操作。

这样,许多棘手的问题就消失了。重复的插入请求不会创建重复,并且在我们拥有数据之前我们不会创建真正的资源。(数据库列可以保持不可为空)。重复的更新请求不会达到不兼容的状态,也不会覆盖后续的更改。无论出于何种原因(客户端崩溃、响应丢失等),客户端都可以(重新)获取并无缝处理原始确认。

连续的删除请求可以查看和处理原始确认,而不会遇到 404 错误。如果事情花费的时间比预期的要长,我们可以临时做出回应,并且我们有一个地方可以让客户检查最终结果。这种模式最好的部分是它的功夫(熊猫)属性。我们采取弱点,即客户在不理解响应时重复请求的倾向,并将其转化为优势:-)

在告诉我这不是 RESTful 之前,请考虑尊重 REST 原则的多种方式。客户端不构建 URL。API 保持可发现性,尽管在语义上有一些变化。HTTP 动词使用得当。如果您认为这是一个巨大的实施变化,我可以根据经验告诉您事实并非如此。

如果您认为要存储大量数据,让我们来谈谈容量:典型的更新确认只有千字节的一小部分。HTTP 当前给您一两分钟的时间来明确响应。即使您只存储一周的操作,客户也有足够的机会赶上。如果您的容量非常大,您可能需要一个专用的符合 acid 的键值存储或内存解决方案。

于 2016-02-18T11:45:38.923 回答
17

对于 REST 服务何时使用 HTTP POST 与 HTTP PUT 方法,似乎总是有些混淆。大多数开发人员会尝试将 CRUD 操作直接关联到 HTTP 方法。我认为这是不正确的,不能简单地将 CRUD 概念与 HTTP 方法相关联。那是:

Create => HTTP PUT
Retrieve => HTTP GET
Update => HTTP POST
Delete => HTTP DELETE

确实,CRUD 操作的 R(etrieve) 和 D(elete) 可以分别直接映射到 HTTP 方法 GET 和 DELETE。然而,混淆在于 C(reate) 和 U(update) 操作。在某些情况下,可以使用 PUT 进行创建,而在其他情况下则需要 POST。歧义在于 HTTP PUT 方法与 HTTP POST 方法的定义。

根据 HTTP 1.1 规范,GET、HEAD、DELETE 和 PUT 方法必须是幂等的,而 POST 方法不是幂等的。也就是说,一个操作是幂等的,如果它可以在一个资源上执行一次或多次并且总是返回该资源的相同状态。而非幂等操作可以将资源的修改状态从一个请求返回到另一个请求。因此,在非幂等操作中,不能保证一定会收到相同的资源状态。

基于上述幂等定义,我对 REST 服务使用 HTTP PUT 方法与使用 HTTP POST 方法的看法是: 在以下情况下使用 HTTP PUT 方法:

The client includes all aspect of the resource including the unique identifier to uniquely identify the resource. Example: creating a new employee.
The client provides all the information for a resource to be able to modify that resource.This implies that the server side does not update any aspect of the resource (such as an update date).

在这两种情况下,可以多次执行这些操作并获得相同的结果。也就是说,资源不会因多次请求操作而改变。因此,一个真正的幂等操作。在以下情况下使用 HTTP POST 方法:

The server will provide some information concerning the newly created resource. For example, take a logging system. A new entry in the log will most likely have a numbering scheme which is determined on the server side. Upon creating a new log entry, the new sequence number will be determined by the server and not by the client.
On a modification of a resource, the server will provide such information as a resource state or an update date. Again in this case not all information was provided by the client and the resource will be changing from one modification request to the next. Hence a non idempotent operation.

结论

不要直接将 CRUD 操作关联和映射到 REST 服务的 HTTP 方法。HTTP PUT 方法与 HTTP POST 方法的使用应基于该操作的幂等性方面。也就是说,如果操作是幂等的,则使用 HTTP PUT 方法。如果操作是非幂等的,则使用 HTTP POST 方法。

于 2013-10-10T04:18:51.123 回答
15

源服务器可以使用该 URI 创建资源

因此,您使用 POST 和可能但不是必需的 PUT 来创建资源。您不必同时支持两者。对我来说,POST 就足够了。所以这是一个设计决定。

正如您的报价所提到的,您使用 PUT 来创建没有分配给 IRI 的资源,并且无论如何您都想创建一个资源。例如,PUT /users/123/password通常用新密码替换旧密码,但如果密码不存在,您可以使用它来创建密码(例如,新注册的用户或通过恢复被禁止的用户)。

于 2014-01-16T07:58:14.947 回答
14

我将登陆以下内容:

PUT 指的是由 URI 标识的资源。在这种情况下,您正在更新它。它是指资源的三个动词的一部分——删除和获取是另外两个。

POST 基本上是一个自由格式的消息,其含义被定义为“带外”。如果消息可以解释为向目录添加资源,那没关系,但基本上您需要了解您正在发送(发布)的消息以了解资源会发生什么。


因为 PUT 和 GET 和 DELETE 指的是一个资源,所以它们在定义上也是幂等的。

POST 可以执行其他三个功能,但是请求的语义会在缓存和代理等中介上丢失。这也适用于为资源提供安全性,因为帖子的 URI 不一定指示它正在应用的资源(尽管它可以)。

一个 PUT 不需要是一个创建;如果资源尚未创建,服务可能会出错,否则更新它。反之亦然——它可以创建资源,但不允许更新。PUT 唯一需要的是它指向一个特定的资源,它的有效负载是该资源的表示。成功的 PUT 意味着(排除干扰)GET 将检索相同的资源。


编辑:还有一件事——一个 PUT 可以创建,但如果它创建了,那么 ID 必须是一个自然 ID——也就是一个电子邮件地址。这样,当您 PUT 两次时,第二次 put 是第一次的更新。这使它具有幂等性

如果生成了 ID(例如新的员工 ID),则具有相同 URL 的第二个 PUT 将创建一个新记录,这违反了幂等规则。在这种情况下,动词是 POST,消息(不是资源)是使用该消息中定义的值创建资源。

于 2013-10-21T21:16:32.953 回答
11

这是一个简单的规则:

应使用PUT到 URL 来更新或创建可位于该 URL 的资源。

POST到 URL 应该用于更新或创建位于某个其他(“从属”)URL 或无法通过 HTTP 定位的资源。

于 2013-12-11T22:15:48.673 回答
10

语义应该是不同的,因为“PUT”和“GET”一样应该是幂等的——这意味着,您可以多次执行相同的 PUT 请求,结果就像您只执行了一次一样。

我将描述我认为最广泛使用和最有用的约定:

当您将资源放在特定的 URL 时,会发生这种情况,它应该保存在该 URL 或类似的东西上。

当您发布到特定 URL 的资源时,您通常会将相关信息发布到该 URL。这意味着 URL 处的资源已经存在。

例如,当你想创建一个新流时,你可以把它放到某个 URL 上。但是,当您想将消息发布到现有流时,您需要发布到其 URL。

至于修改流的属性,您可以使用 PUT 或 POST 来完成。基本上,只有在操作是幂等的时候才使用“PUT”——否则使用 POST。

但是请注意,并非所有现代浏览器都支持 GET 或 POST 以外的 HTTP 动词。

于 2011-10-23T20:07:55.460 回答
10

大多数时候,你会像这样使用它们:

  • 资源发布到集合中
  • PUT由 collection/:id 标识的资源

例如:

  • 发布/项目
  • 放置 /items/1234

在这两种情况下,请求正文都包含要创建或更新的资源的数据。从路由名称中应该可以看出 POST 不是幂等的(如果你调用它 3 次它会创建 3 个对象),但 PUT 是幂等的(如果你调用它 3 次结果是一样的)。PUT 通常用于“upsert”操作(创建或更新),但如果您只想使用它进行修改,则始终可以返回 404 错误。

请注意,POST 在集合中“创建”一个新元素,而 PUT 在给定 URL 处“替换”一个元素,但使用 PUT 进行部分修改是一种非常常见的做法,即仅使用它来更新现有资源和仅修改正文中包含的字段(忽略其他字段)。这在技术上是不正确的,如果你想成为 REST 纯粹主义者,PUT 应该替换整个资源,你应该使用 PATCH 进行部分更新。只要行为在所有 API 端点中清晰且一致,我个人并不在意。

请记住,REST 是一组让您的 API 保持简单的约定和指南。如果您最终只是为了检查“RESTfull”框而进行了复杂的解决方法,那么您就没有达到目的;)

于 2017-06-21T17:38:44.630 回答
8

虽然可能有一种不可知论的方式来描述这些,但它似乎与来自网站答案的各种陈述相冲突。

让我们在这里非常清楚和直接。如果您是使用 Web API 的 .NET 开发人员,事实是(来自 Microsoft API 文档), http://www.asp.net/web-api/overview/creating-web-apis/creating-a-web -api-that-supports-crud-operations

1. PUT = UPDATE (/api/products/id)
2. MCSD Exams 2014 -  UPDATE = PUT, there are **NO** multiple answers for that question period.

当然,您“可以”使用“POST”进行更新,但只需按照给定框架为您制定的约定即可。就我而言,它是 .NET / Web API,所以PUT 用于 UPDATE没有争议。

我希望这可以帮助任何使用 Amazon 和 Sun/Java 网站链接阅读所有评论的 Microsoft 开发人员。

于 2014-07-21T20:02:35.833 回答
8

如果你熟悉数据库操作,有

  1. 选择
  2. 插入
  3. 更新
  4. 删除
  5. 合并(如果已经存在则更新,否则插入)

PUT用于合并和更新类似操作并POST用于插入。

于 2016-06-29T21:13:07.827 回答
6

在实践中,POST 非常适合创建资源。新创建资源的 URL 应在 Location 响应标头中返回。PUT 应该用于完全更新资源。请理解,这些是设计 RESTful API 时的最佳实践。HTTP 规范本身不限制使用 PUT/POST,但对创建/更新资源有一些限制。查看总结了最佳实践的http://techoctave.com/c7/posts/71-twitter-rest-api-dissected 。

于 2014-10-06T06:51:56.893 回答
4

POST:使用它来创建新资源。这就像具有自动递增 ID 的 INSERT(SQL 语句)。在响应部分,它包含一个新生成的 Id。

POST 也用于更新记录。

PUT:使用它来创建新资源,但在这里我知道身份密钥。这就像我事先知道身份密钥的 INSERT(SQL 语句)。在响应部分它什么也不发送。

PUT 也用于更新资源

于 2013-12-12T11:06:52.543 回答
4

概括

  • 用于使用请求中包含的表示定义PUT的状态来创建或替换目标资源的状态。这种标准化的预期效果是幂等的,因此它通知中介他们可以在通信失败的情况下重复请求。
  • 以其他方式使用POST(包括创建或替换目标资源以外的资源的状态)。它的预期效果没有标准化,因此中介不能依赖任何普遍的财产。

参考

RFC 7231 (Roy Fielding, Julian Reschke, 2014)中给出了关于 thePOSTPUTrequest 方法之间语义差异的最新权威描述:

POST和方法之间的根本区别在于PUT封闭表示的不同意图。请求中的目标资源POST旨在根据资源自身的语义处理封闭的表示,而PUT请求中的封闭表示被定义为替换目标资源的状态。因此,intent 的意图PUT是幂等的并且对中介可见,即使确切的效果只有源服务器知道。

换句话说,预期效果PUT标准化的(使用请求中包含的表示定义的状态创建或替换目标资源的状态),因此对所有目标资源都是通用的,而预期效果POST不是标准化的,并且所以特定于每个目标资源。因此POST可以用于任何事情,包括实现PUT和其他请求方法(GETHEADDELETECONNECTOPTIONSTRACE)的预期效果。

但建议始终使用更专业的请求方法,而不是POST在适用的情况下,因为它为中介提供更多信息以自动检索信息(因为GETHEADOPTIONSTRACE被定义为安全的)、处理通信故障(因为GETHEADPUTDELETEOPTIONSTRACE被定义为idempotent),并优化缓存性能(因为GETHEAD被定义为cacheable),如使用 POST 可以(Roy Fielding,2009)中所述:

POST只有在其他方法非常适合的情况下使用它才会成为问题:例如,检索应该是某种资源的表示的信息 ( GET)、完全替换表示 ( PUT) 或任何其他标准化告诉中间人一些比“这可能会改变一些事情”更有价值的方法。其他方法对中介更有价值,因为它们说明了如何自动处理故障以及中间缓存如何优化它们的行为。POST没有这些特征,但这并不意味着我们可以没有它。POST在 HTTP 中有许多有用的用途,包括“此操作不值得标准化”的一般用途。</p>

于 2020-12-04T20:56:49.650 回答
4

对我来说,理解差异的关键是了解谁定义了资源的 ID:

示例(带有一些地址服务)

POST (sever creates new resource)

client               server/addresses      // NOTE: no ID in the request
  |                                 |
  | --{POST address data}-->        |
  |                                 |
  | <--{201, created addresses/321} |      // NOTE: resource ID in the reply
  |                                 |
PUT (sever sets data of resource, creating it if necessary)

client               server/addresses/321      // NOTE: *you* put the ID here!
  |                                 |
  | --{PUT address data (to 321)}-->|
  |                                 |
  | <--{201, created }              |          // NOTE: resource ID not required here
  |                                 |

下面有很多很棒的答案,里面有很多细节,但这帮助我明白了这一点。

于 2021-09-17T09:51:46.443 回答
2

我认为在这个 PUT vs POST 问题上还有一个有趣的观点没有分享:

如果您想要一个无需 JavaScript 的 Web 应用程序(例如,如果有人使用 Lynx 之类的命令行浏览器或 NoScript 或 uMatrix 之类的浏览器插件),您将不得不使用 POST 发送数据,因为 HTML 表单仅支持GET 和 POST HTTP 请求。

基本上,如果您想使用渐进增强 ( https://en.wikipedia.org/wiki/Progressive_enhancement ) 让您的 Web 应用程序在任何地方都可以工作,无论是否使用 JavaScript,您都不能使用其他 HTTP 方法,例如 PUT 或 DELETE,它们只是在 HTTP 1.1 版中添加。

于 2019-06-26T09:01:14.333 回答
2

除了以上所有答案:


最常用于专业实践,


  • 我们在CREATE操作中使用 PUT over POST 。为什么?因为这里的许多人也说过,响应是不可缓存的,而 POST 是(需要内容位置和过期)。
  • 我们在UPDATE操作中使用 POST over PUT 。为什么?因为它使整个包含资源的缓存副本无效。这在更新资源时很有帮助。
于 2019-09-20T13:31:12.257 回答
1

那么,应该使用哪一个来创建资源呢?还是需要两者都支持?

你应该使用PATCH. 您修补问题列表,例如

PATCH /questions HTTP/1.1

带有一个包含您要创建的对象的列表,例如

[
    {
        "title": "I said semantics!",
        "content": "Is this serious?",
        "answer": "Not really"
    }
]

这是一个 PATCH 请求

  • 您修改现有资源列表而不提供全新内容
  • 您在不提供所有数据的情况下将新问题的状态从不存在更改为存在(服务器很可能会添加一个id)。

这种方法的一大优点是您可以使用单个请求创建多个实体,只需在列表中提供它们。

PUT显然是做不到的。您可以POST用于创建多个实体,因为它是 HTTP 的厨房接收器,并且基本上可以做所有事情。

一个缺点是可能没有人使用PATCH这种方式。恐怕,我只是发明了它,但我希望,我提供了一个很好的论据。

您可以CREATE改用,因为允许自定义 HTTP 动词,只是它们可能不适用于某些工具。

关于语义,CREATE恕我直言是唯一正确的选择,其他一切都是圆孔中的方钉。不幸的是,我们只有圆孔。

于 2018-05-08T02:39:46.850 回答
1

上面和下面的所有答案都是正确的,只是一个小(重要)说明。所有这些“动词”都是建议,它们的效果没有强制执行。服务器可以自由地做他们想做的任何事情,这意味着使用 GET 或服务器想要的任何内容进行编写。这一切都取决于实现后端。

例如 PHP,读取$_POST$_GET. 通过从这些数组中读取变量将完成什么完全取决于程序员。

于 2021-10-11T05:54:05.137 回答
1

POST用于向服务器发送数据。
PUT用于将数据存放到服务器上的资源(例如,文件)中。

我在HTTP: The Definitive Guide一书的脚注(第 55 页)中看到了这一点。

于 2021-11-21T14:11:14.887 回答