REST中的PUT与POST


5370

根据HTTP / 1.1规范:

POST方法用来请求原始服务器接受被附在请求由标识的资源的新下属实体Request-URIRequest-Line

换句话说,POST用于创建

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

PUT用于创建或替换

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


56
使用HTTPbis中的定义可能会有所帮助-Roy投入了大量工作来阐明它们。请参阅:tools.ietf.org/html/...
马克诺丁汉

16
只是为了将@MarkNottingham的评论带到最新的修订版中,这是HTTPbis上定义的POSTPUT
Marius Butuc 2012年

37
在我看来,这种争论源于通过以CRUD操作描述HTTP方法而过度简化REST的普遍做法。
Stuporman

5
不幸的是,关于POST的第一个答案是错误的。检查我的答案以更好地解释这些差异:stackoverflow.com/a/18243587/2458234
7hi4g0

23
PUT和POST都是不安全的方法。但是,PUT是幂等的,而POST不是。-详情请访问:restcookbook.com/HTTP%20Methods/put-vs-post/…–
Dinesh Saini

Answers:


4235

总体:

PUT和POST均可用于创建。

您必须问“您要对该动作执行什么操作?” 来区分您应该使用的内容。假设您正在设计一个用于询问问题的API。如果要使用POST,则可以对一系列问题进行处理。如果要使用PUT,则可以对特定问题进行操作。

两者都可以使用,因此在RESTful设计中应该使用哪一个:

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

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

一些注意事项:

  • 您是否命名您明确创建的URL对象,还是由服务器决定?如果命名,请使用PUT。如果让服务器决定,则使用POST。
  • 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来创建URL。这将导致“找不到资源”错误,因为<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具有该状态。


1024
我认为不能足够强调PUT是幂等的事实:如果网络陷入僵局,并且客户端不确定他的请求是否通过,则可以将其发送第二次(或第100次),并且由发送方保证。 HTTP规范,它与一次发送具有完全相同的效果。
约尔格W¯¯米塔格

77
@JörgW Mittag:不需要。如果请求在此期间同时被其他用户或第一个请求本身修改,则第二次可能返回409冲突或其他内容。
Mitar

629
如果我没记错的话,我们应该强调的是,PUT被定义为幂等的。您仍然必须以PUT正确运行的方式编写服务器,是吗?也许最好说“ PUT使传输假定为幂等,这可能影响传输的行为,例如缓存”。
伊恩·尼·刘易斯

150
@JörgWMittag幂等流行语?那么“发送和发送并发送我的朋友,最终没什么关系。”
James Beninger

39
将它们视为:PUT =插入或更新;POST =插入。因此,当您进行两个PUT时-您将获得一个新记录,当您进行两个POST时-您将获得两个新记录。
Eugen Konkov,

2217

您可以在网络上找到这样的断言:

两者都不对。


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

PUT意味着放置资源-用另一件事完全替换给定URL上可用的任何内容。根据定义,PUT是幂等的。随意执行多次,结果是相同的。x=5是幂等的。您可以放置​​一个资源,无论它先前是否存在(例如,创建或更新)!

POST更新资源,添加辅助资源或引起更改。POST不是幂等的,也不x++是幂等的。


通过此参数,PUT用于在您知道要创建的事物的URL时进行创建。当您知道要创建的事物类别的“工厂”或管理者的URL时,可以使用POST进行创建。

所以:

POST /expense-report

要么:

PUT  /expense-report/10929

72
我同意,无论在哪里考虑到幂等性,它都应该胜过其他任何问题,因为弄错这个错误可能会导致许多意外错误。
乔什(Josh)2010年

16
如果POST可以更新资源,那不是幂等的?如果我使用PUT更改学生年龄,并且做10倍,那么如果我做过一次,学生年龄是相同的。
杰克·乌克丽雅

28
@Schneider,在这种情况下,您的服务器将付出额外的努力来保证幂等,但它并未在广告它。如果浏览器尝试重新加载这样的POST请求,仍会警告用户。
东武2012年

47
@Schneider POST可以创建辅助资源;因此,您可以POST到集合,例如POST / expense-reports,即使您的请求数量完全相似,它也会在服务器上创建与发送的请求数量一样多的实体(费用报告)。可以将其视为使用自动递增的主键在数据库表(/ expense-reports)中插入同一行。数据保持不变,密钥(在这种情况下为URI)由服务器生成,并且对于每个其他插入(请求)而言都是不同的。因此,POST效应可以是幂等的,但也可能不是。因此,POST 不是幂等的。
Snifff 2012年

11
假设我们有可能具有两个属性的实体- namedate。如果我们有一个具有name和的实体date,然后向其请求仅指定一个name,则PUT的正确行为是消除date该实体的,而POST可能仅更新指定的属性,而保留未指定的属性在提出要求之前。这听起来是否正确/合理,还是对PUT的使用不当(我看到了对PATCH的引用,这似乎更合适,但尚不存在)?
Jon z

706
  • POST到URL 服务器定义的URL上创建子资源
  • 放置到URL 客户端定义的 URL上完整地创建/替换资源
  • 对URL进行PATCH 更新会在该客户端定义的URL上更新资源的一部分

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

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

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

因此:在创建资源之前,PUT仅是CREATE的候选对象,在此客户端客户已经知道该URL。例如。/blogs/nigel/entry/when_to_use_post_vs_put作为标题用作资源密钥

如果已存在,则PUT将替换已知URL处的资源,因此两次发送相同的请求无效。换句话说,对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,而不是具有不同邮寄地址字段值的“ Customer”资源的PUT。

摘自REST API设计-Thoughtworks的Prakash Subramaniam编写的资源建模

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


53
或从隔离层的另一面:如果客户端确定了结果资源的地址,则输入PUT;如果服务器确定了结果,则输入POST。
DanMan 2012年

3
我认为应该对这个答案进行编辑,以使其以一种非常简单的方式更加清楚@DanMan指出的内容。我在这里发现最有价值的是最后的注释,该注释指出PUT仅应用于替换整个资源。
爱马仕(Hermes)

3
至少几年来,PATCH都不是现实的选择,但是我同意这种思想。
暗恋

4
我试图理解,但是仅当客户端确定知道资源尚不存在时,才使用PUT创建内容才有意义,对吗?以博客示例为例,假设您在几年内创建了数百篇博客文章,然后不小心选择了与两年前的帖子相同的标题。现在您已经离开了,并替换了原本不想要的那个帖子。因此,使用PUT进行创建将需要客户端跟踪采取了什么以及没有采取什么,并且可能导致事故和意外的副作用,以及具有执行两种完全不同的功能的路线?
galaxyAbstractor 2015年

5
你是对的。将博客文章放在与现有文章相同的URL上将导致对该现有文章的更新(尽管您显然可以先使用GET进行检查)。这说明了为什么仅使用标题作为URL是一个不好的主意。但是,它可以在任何有数据自然键的地方工作……以我的经验,这是罕见的。或者,如果您使用了GUID
Nigel Thorne,2015年

221

摘要:

创建:

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

在/ resources URI或collection下使用newResourceId作为标识符创建THE新资源。

PUT /resources/<newResourceId> HTTP/1.1 

开机自检

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

POST /resources HTTP/1.1

更新:

可以用下面的方式PUT进行:

在/ resources URI或collection下,以现存资源为标识更新资源。

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

您正在将新用户发布到用户 集合

如果继续尝试以下操作:

POST /users/john HTTP/1.1

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

使用PUT后,您将引用资源或单个项目,可能在collection中。所以当你说:

PUT /users/john HTTP/1.1

您要告诉服务器更新,或者在用户集合下创建john 资源(如果不存在)。

规格:

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

开机自检

POST方法用来请求原始服务器接受封闭在请求作为实体的新下属的请求URI中使用Request-Line标识的资源的

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

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

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

参考:


11
这篇文章对我的理解很有帮助,因为POST将“内容”作为子元素添加到给定的集合(URI)中,而PUT在给定的URI位置显式定义了“内容”。

3
这是最好的答案,在这里,我认为:这个“ POST都不能更新资源”都是胡说八道。我喜欢您的说法,“只能通过PUT执行更新”。
汤玛斯(Thomas)

4
不,PUT不可用于更新或创建。用于替换。请注意,您不能用创建内容来代替任何东西。
thecoshman

2
@ 7hi4g0 PUT用于进行完整替换,换言之,替换。您可以用任何东西代替什么,或者用全新的东西代替。PUT并不是要进行较小的更改(除非您让客户端进行较小的更改,并提供整个新版本,甚至保持不变)。对于部分修改,PATCH是选择的方法。
thecoshman 2015年

1
@thecoshman您可以,但是不清楚create是否也包含在其中。在这种情况下,最好是明确的。
7hi4g0

175

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

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

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

PUT要example.com/users/id,因为您要替换/创建特定用户。

使用相同的数据进行两次发布意味着创建两个具有不同ID的相同用户。使用相同的数据两次输入将首先创建用户,第二次将其更新为相同状态(无更改)。由于PUT无论执行多少次,您最终都会处于相同状态,因此每次都被称为“同等效力”-等幂。这对于自动重试请求很有用。按下浏览器上的“后退”按钮时,不再“确定要重新发送”。

一般建议是POST在需要服务器控制URL资源生成时使用。PUT否则使用。身高PUT 超过POST


12
过于草率可能导致人们普遍认为您只需要两个动词:GET和POST。GET获取,POST更改。使用POST甚至可以执行PUT和DELETE。问25年后PUT到底意味着什么,也许这是我们最初发现它是错误的信号。REST的流行使人们回到了现在必须学会克服过去的错误的基础知识。POST被滥用,现在通常被错误地教导。最好的部分:“使用相同的数据进行两次发布意味着创建两个相同的[资源]”。好点!
maxpolk 2014年

1
您如何使用PUT通过ID创建记录,例如在您的示例中(user 5如果尚不存在)?不是update, replace if already exists吗 或什么
路加福音

@库尔顿:我的意思是我写的。如果将PUT放到/ users / 5且#5尚不存在,则插入用户5。
2014年

@Coulton:并且PUT还可以用于整体替换现有资源的价值。
DavidRR 2014年

1
“在POST上优先使用PUT” ...可以证明这一点吗?
thecoshman

173

我想补充一下我的“务实”建议。当您知道可以检索保存的对象的“ 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

17
实际上,应该是POST /users。(请注意/users是复数。)这具有创建新用户并将其作为/users集合的子资源的作用。
DavidRR 2014年

6
@DavidRR说句公道话,如何处理小组完全是另一场辩论。GET /users这很有意义,它可以根据需要进行读取,但是我对GET /user/<id>or或POST /user(对于所述新用户使用有效负载)没问题,因为它正确地读取了“让我用户5”很奇怪,但“让我用户5”更自然。我可能还是会
倒退

126

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

PUT    /items/1      #=> update
POST   /items        #=> create

4
POST /items将新项目添加到已定义的资源(“项目”)中。如答案所示,它不是“创建组”。我不明白为什么会有12票。
David J.

开箱即用,Rails不支持通过REST“创建组”。要“创建组”(我的意思是“创建资源”),您必须通过源代码来完成。
David J.

8
这是一个公平的准则,但过于简单。正如其他答案所述,这两种方法都可以用于创建和更新。
布莱德·科赫

2
我同意这个回答,但稍作修改。使用POST创建并使用PUT完全更新资源。对于部分更新,我们可以使用PUT或PATCH。假设我们要更新组的状态。我们可以将PUT / groups / 1 / status的状态
设为

2
还应该明确指出,这PUT /items/42对于创建资源也是有效的,但前提是客户端具有命名资源的特权。(Rails是否允许客户享有此命名特权?)
DavidRR 2014年

123

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

在此处输入图片说明

比喻:

  • 放置,即放在原处。
  • 邮局以邮寄方式发送邮件。

在此处输入图片说明

社交媒体/网络类比:

  • 在社交媒体上:当我们发布的消息,它创造了新的岗位。
  • 放入(即编辑)我们已经发布的消息。

21
@MobileMon不,REST方法不是CRUD。
jlr

1
我想说说UPSERTS的投入
Hola Soy Edu Feliz Navidad

@MobileMon否:创建新资源且不知道获取该资源的最终端点时,请进行POST。PUT其他情况。
Portekoi

67

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。


8
允许PUT创建资源没有错。请注意,这意味着客户端提供了URL。
朱利安·雷施克

5
允许PUT创建资源有一个非常错误的地方:客户端提供URL。这就是服务器的工作!
Joshcodes

@Joshcodes并非总是这样,创建客户端ID是服务器的工作。我越来越多地看到允许客户生成某种UUID作为资源ID的设计。这种设计特别适合扩大规模。
贾斯汀·欧姆斯

@JustinOhms我同意您关于客户端生成的ID的观点(旁注:我自2008年以来设计的所有系统都要求客户端将ID创建为UUID / Guid)。这并不意味着客户端应指定URL。
Joshcodes

1
是的,如果资源已经存在,请使用PUT。但是,几乎在所有情况下,都应该使用POST创建资源,并且客户端不应提供URL。罗伊·菲尔丁(Roy Fielding)同意FWIW的这一声明:roy.gbiv.com/untangled/2008/rest-apis-must-be-Hypertext-driven
Joshcodes

61

是否使用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-超文本驱动

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

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

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

第6步是人们通常对要做的事情感到困惑的地方。但是,没有理由创建一个解决方案来解决此问题。相反,可以按照RFC 2616中的指定使用HTTP ,并且服务器会回复:

10.4.10 409冲突

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

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

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

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

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

基于RFC 7231版本的更新以替换2616

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

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

现在可能很想在重复POST的情况下简单地返回303。但是,事实恰恰相反。仅当多个创建请求(创建不同的资源)返回相同的内容时,才返回303。一个示例是“谢谢您提交请求消息”,客户端无需每次都重新下载。RFC 7231在第4.2.2节中仍然保持POST不等幂,并继续保持POST应该用于创建。

有关此的更多信息,请阅读本文


409冲突响应是否适合尝试使用现有用户名创建新帐户之类的代码?我一直在使用409专门解决版本冲突,但是在阅读了您的答案之后,我想知道是否不应将其用于任何“重复”请求。
Eric B.

@EricB。是的,在这种情况下,您描述为“由于与资源的当前状态冲突”,操作将失败。此外,可以合理预期用户可以解决冲突,并且消息正文仅需要通知用户该用户名已存在。
Joshcodes 2014年

@Joshcodes您能对冲突解决过程说更多吗?在这种情况下,如果用户名已经存在,客户端是否希望提示最终用户输入其他用户名?如果客户端实际上试图使用POST来更改用户名怎么办?PUT请求是否仍应用于更新参数,而POST用于创建对象(无论一次还是多次)?谢谢。
BFar

@ BFar2如果用户名已经存在,则客户端应提示用户。要更改用户名,假设用户名是已创建的需要修改的资源的一部分,则将使用PUT,因为您是正确的,使用POST进行创建,始终使用PUT进行更新。
Joshcodes

使用简短有效的语言来解释事物也是一种可取的技能
Junjun Liu

53

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

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

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

我将其解释为对PUT的幂等要求,以表示:

  • POST非常适合在集合下创建新对象(并且create不必是幂等的)
  • PUT非常适合更新现有对象(并且更新必须是幂等的)
  • POST也可以用于对现有对象进行非幂等更新(特别是在不指定整个对象的情况下更改对象的一部分)-如果您考虑一下,创建集合的新成员实际上是这种情况的一种特殊情况。从集合的角度进行更新)
  • 当且仅当您允许客户端命名资源时,PUT还可用于创建。但是由于REST客户端不应该对URL结构进行假设,因此就本来打算而言,这样做就少了。

3
“ POST也可以用于对现有对象进行非幂等更新(特别是在不指定整个对象的情况下更改对象的一部分)”,这就是PATCH的目的
Snuggs,2012年

48

简而言之:

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

开机自检是非幂等的,如果多次执行操作与一次执行相比,资源状态可能会有所不同。

类比数据库查询

PUT你能想到的类似“UPDATE STUDENT SET地址= ”ABC“其中id =” 123" ;

开机自检您可以想到类似“ INSERT INTO STUDENT(name,address)VALUES(“ abc”,“ xyzzz”);

学生ID是自动生成的。

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

对于POST,如果多次执行同一查询,则将在数据库中创建多个Student记录,并且每次执行“ INSERT”查询时数据库状态都会更改。

注意: PUT需要一个需要更新的资源位置(已有资源),而POST则不需要。因此,直观上来说,POST是用于创建新资源的,而PUT是更新现有资源所必需的。

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


6
用于PUT类似于INSERT或UPDATE查询
Eugen Konkov

1
实际上,您可以想到类似于“ UPDATE STUDENT SET address =“ abc”其中id =“ 123”;的PATCH语句。“ UPDATE STUDENT SET address =” abc“,name =” newname“其中id =” 123“是PUT的正确比喻
mko

Put也可以用于INSERT。例如,如果服务器检测到您试图多次上传同一文件,则将使您的请求成为幂等。(没有新文件上传完成)。
kiwicomb123

43

POST就像将信件投递到邮箱或将电子邮件投递到电子邮件队列一样。PUT就像将对象放在小孔或架子上的某个位置(它具有已知地址)时一样。

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

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

一般规则:如果您知道商品的ID或名称,请使用PUT。如果要由接收方分配项目的ID或名称,请使用POST。

POST与PUT


1
不,PUT表示您知道URL。如果仅知道ID,则使用该ID POST以获取URL。
Joshcodes

6
ID是URL的一部分,因此,是的,如果您知道URL(包括ID),请使用PUT。
2013年

不,URL由服务器确定,并且ID不一定是URL的一部分。罗伊·菲尔丁(Roy Fielding)会告诉你同样的话,或者你可以阅读他的论文
Joshcodes

@Joshcodes,这是否假设是REST?在RESTful架构中,项目ID最明确地是URL的一部分,如:/ people / 123。我喜欢这个用于REST的网站:microformats.org/wiki/rest/urls
Beez 2013年

1
@Beez mircoformats链接为服务器构造其URL 提供了一种好方法,但是服务器可以确定URL。客户端永远不会这样做。如果您不了解,请参阅我的答案或相关文章
Joshcodes 2014年

39

新答案(现在我对REST有了更好的了解):

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

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

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

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

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

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

PUT /something(如果/something已经存在的话):“随便/something拿什么,用我给你的东西代替。”

PUT /something(如果/something尚不存在):“接受我给你的东西,放在上面/something。”

POST /something:“接受我给您的东西/something,只要完成就给它URL ,就把它放在任何您想要的地方。”


但是,当您的ID生成方法为“自动增量”时,如何使用PUT创建不存在的新资源?通常,ORM会自动为您生成ID,例如您希望其在POST中的方式。这是否意味着如果您想以正确的方式实现PUT,就必须更改id自动生成?如果答案是肯定的,这很尴尬。
罗尼·阿克塞拉德

1
@RoniAxelrad:PUT就像一个数据库“ INSERT OR UPDATE”语句,在其中将键包括在该语句中,因此仅适用于不引起冲突的情况。例如。您的域具有“自然键”,或者您使用的是GUID。POST就像使用自动递增键插入表中一样。数据库必须告诉您插入后获得的ID。请注意,“ INSERT OR UPDATE”将替换任何先前的数据(如果存在)。
奈杰尔·索恩

@NigelThorne感谢您的回答。因此,例如,如果我尝试使用URI放置一本ID为10的图书:PUT books / 10。如果不存在编号为10的图书,则应该创建编号为10的图书,对吗?但我无法控制创建ID分子,因为它是自动递增的。在那种情况下我该怎么办?
罗尼·阿克塞拉德

1
将@RoniAxelrad REST PUT设置为不存在的ID是对服务器创建资源的请求。服务器仍然可以决定是否要允许它。服务器负责。它可以回答“不。我不会那样做”。如果用户没有足够的权限,您已经这样做了……等等。服务器说“不”是可以的。REST是一个约定,可让我们定义各种类型的请求的含义...您的服务器根据您的业务逻辑决定如何处理这些请求:)即使它说“不”,它仍然遵循REST :)
Nigel Thorne

38

简短答案:

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

长答案:

开机自检:

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

放:

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

更长的答案:

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

从REST架构的角度来看,没有任何关系。如果没有PUT,我们也可以生活。但是从客户开发人员的角度来看,这使他/她的生活变得简单得多。

在进行PUT之前,客户端无法直接知道服务器生成的URL,或者客户机是否全部生成了URL,也无法知道要发送到服务器的数据是否已更新。PUT减轻了开发人员的所有这些麻烦。PUT是幂等的,PUT处理竞争条件,并且PUT让客户端选择URL。


3
您的简短答案可能非常错误。HTTP代理可以自由重复HTTP PUT。因此,如果PUT实际上正在执行SQL INSERT,则它可能第二次失败,这意味着它将返回不同的结果,因此它不会是IDEMPOTENT(这是PUT和POST之间的区别)
KamilTomšík,

36

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

RFC 5789说到PATCH(自1995年起):

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

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


27

冒着重述已经说过的风险的危险,记住PUT意味着客户端在创建资源时控制URL最终要成为的样子似乎很重要。因此,在PUTPOST之间进行选择的一部分将取决于您可以信任客户端提供正确的标准化URL的程度。与您的URL方案一致的。

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


2
我有点迟了-但是有人在另一个网站上说类似的话就可以点击它。如果要创建资源并使用自动递增的ID作为其“标识符”,而不是用户分配的名称,则它应该是POST。
Ixmatus 2012年

2
这不太正确-PUT仍然可以通过使用非规范名称来引用资源来创建资源,只要在响应中,服务器返回的Location标头中确实包含规范资源名称。
以太

1
@Joshcodes不会忘记您可以有许多URI引用相同的基础资源。因此,以太所说的是合理的建议,客户端可以将URL放置到URL(可能更语义化,例如PUT /X-files/series/4/episodes/max)上,而服务器使用URI进行响应,该URI提供到该新资源的短规范唯一链接(即/X-Ffiles/episodes/91
thecoshman

@thecoshman问题在于URL结构不属于客户端。阅读有关自我发现(也是REST的一部分)的知识可能有助于使这一点变得清楚。
Joshcodes,2015年

@Joshcodes然后按照这种逻辑,客户端应该永远不要使用PUT来创建,因为它们不必关心提供URL。好吧...除非服务器向客户端提供了一个URL到PUT,否则客户端可能会响应“ 204 / comments / 234532”,例如“ PUT / comments / new”,但这似乎有点RPC给我,客户端应该只发布到/ comments ...
thecoshman 2015年

24

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

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

情况2:如果您的朋友第一次评论您的帖子,这也会在数据库中创建一个新条目,因此将使用POST方法。

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

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


4
如果注释是具有诸如用户ID,创建日期,注释消息等属性的对象,并且在编辑时仅注释消息正在更新,那么应该在此处进行PATCH吗?
Habeeb Perwad '17

FB使用PUT更新注释,因为正在更新现有资源,这就是PUT所做的(更新资源)。与POST相比,PUT恰好是幂等的。HTTP动词是幂等的,会影响错误处理,但不会决定用法。见我的回答一个更详细的解释:stackoverflow.com/questions/630453/put-vs-post-in-rest/...
Joshcodes

21

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

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

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

其他一些注意事项:

  • POST使整个包含资源的缓存副本无效(更好的一致性)
  • POST响应时,PUT响应不可缓存(需要Content-Location和到期)
  • Java ME,较旧的浏览器,防火墙不支持PUT

这是不正确的。对于POST,也只有在第一次成功重试之前,状态才是未定义的。然后,服务器要么接受POST(消息从未到达),要么为重复的ID(消息到达,响应丢失)引发409冲突,要么是其他有效响应。
Joshcodes

通常,用户代理程序无法安全地重试POST操作,因为POST操作不能保证两个操作与一个操作具有相同的效果。术语“ ID”与HTTP无关。URI标识资源。
汉斯·马尔赫贝

用户代理可以根据需要多次“安全”重试POST操作。它只会收到重复的ID错误(假设资源有一个ID)或重复的数据错误(假设这是一个问题,并且资源没有ID)。
Joshcodes 2014年

刘海头靠墙。HTTP没有解决可靠性问题的方法,并且对此了解不多,讨论不多,并且在大多数Web应用程序中根本无法解决。@Joshcodes我对这个问题有一个答案。我基本上同意汉斯的观点。有问题
bbsimonbb

@ bbsimonbb,HTTP具有一组可靠且有据可查的错误响应。我对这个问题的回答(stackoverflow.com/questions/630453/put-vs-post-in-rest/…)涵盖了如何根据规范使用http来实现一致性。
Joshcodes

17

对于该主题的新手读者会被无休止的关于您该做什么的讨论以及相对缺乏经验教训所吸引。我想,REST是比SOAP更为“优选”的事实,这是从经验中学到的高级知识,但是,天哪,我们一定已经取得了进步吗?是2016年。罗伊(Roy)的论文是2000年。我们开发了什么?它有趣吗?整合起来容易吗?支持?它可以应对智能手机和不稳定的移动连接的兴起吗?

据我说,现实生活中的网络是不可靠的。请求超时。连接被重置。网络一次会中断数小时或数天。火车与移动用户一起进入隧道。对于任何给定的请求(在本次讨论中都会偶尔承认),请求可能会掉入途中,或者响应可能会掉回途中。在这种情况下,直接针对实质性资源发出PUT,POST和DELETE请求总是让我感到有些野蛮和天真。

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

或者,您可以这样做:将不安全的请求视为短暂的单用户资源(我们称其为操作)。客户端请求对该实体资源执行新的“操作”,同时对该资源执行空POST。POST仅用于此目的。一旦安全地拥有了刚创建的动作的URI,客户端就会将不安全的请求放到动作URI,而不是目标资源。解决该操作并更新“实际”资源完全是您API的工作,并且在这里与不可靠的网络分离。

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

您将很快发现Promise与Promise的相似之处:我们在做任何事情之前都会为结果创建并返回占位符。就像承诺一样,动作可以一次成功或失败,但是其结果可以重复获取。

最重要的是,我们使发送和接收应用程序有机会将唯一标识的操作与各自环境中的唯一性相关联。我们可以开始要求并强制执行!来自客户的负责任的行为:尽可能多地重复您的请求,但是直到您从现有请求中获得确定的结果后,再进行新的操作。

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

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

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

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


1
不会存储响应就像维护会话吗?这将导致(水平)缩放问题。
萨拉·哈万德

17

除了其他人建议的差异外,我还要添加一个。

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方法


3
为什么不赞成?如果为真,这是一个关键的区别,不是吗?
Iofacture

2
我在实现用于个人资料更新的API时遇到了它,其中包括用户个人资料图片上传。然后,我以邮递员Ajax,PHP curl和laravel 5.6作为后端对其进行了测试。
罗希特·迪曼

14

对于何时将HTTP POST与HTTP PUT方法用于REST服务似乎总是有些困惑。大多数开发人员将尝试将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方法。


2
更新=> HTTP POST:POST不用于更新
Premraj'1

@premraj您假设Burhan告诉您不要这样做;也就是说,您正在混合CRUD,REST和HTTP。如果阅读定义了这些内容的RFC 7231,您会发现在HTTP协议中POST的定义当然允许更新。否则,只有REST的约束。
IAM_AL_X

13

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

因此,您可以使用POST,并且可能(但不是必须)使用PUT创建资源。您不必同时支持两者。对我来说,POST就足够了。因此,这是一个设计决策。

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


我认为您已经成功地提供了一些使用PUT的很好的例子之一。
thecoshman

12

我将使用以下内容:

PUT是指由URI标识的资源。在这种情况下,您将对其进行更新。它是涉及资源的三个动词的一部分-删除并成为另外两个。

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


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

POST可以执行其他三个功能,但是请求的语义将在诸如缓存和代理之类的中介上丢失。这也适用于在资源上提供安全性,因为帖子的URI不一定表示它要应用于的资源(虽然可以)。

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


编辑:还有一件事-PUT可以创建,但是如果这样做,则ID必须是自然ID-也就是电子邮件地址。这样,当您两次输入PUT时,第二个Put就是对第一个Put的更新。这使其成为幂等

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


9

语义是不同的,因为“ PUT”就像“ GET”一样是幂等的-意思是,您可以多次执行相同的确切PUT请求,结果就像只执行一次一样。

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

当您将资源放在特定URL处时,会发生的情况是应将其保存在该URL或类似的行上。

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

例如,当您要创建新的流时,可以将其放置到某个URL。但是,当您想要将消息发布到现有流时,可以将其发布到其URL。

至于修改流的属性,可以使用PUT或POST完成。基本上,仅当操作是幂等时才使用“ PUT”-否则使用POST。

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


您所描述的POST实际上就是PATCH应该如何表现。POST应该意味着更类似于“附加”,如“发布到邮件列表”中一样。
2014年

8

大多数时候,您将像这样使用它们:

  • POST资源到一个集合
  • 放置由collection /:id标识的资源

例如:

  • POST /项目
  • PUT /项目/ 1234

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

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

请记住,REST是一组使您的API保持简单的约定和准则。如果最终只是为了检查“ RESTfull”框而遇到了一个复杂的变通方法,那么您将无法达到目的;)


7

尽管可能有一种不可知的描述方式,但它似乎与网站答案中的各种陈述相冲突。

让我们在这里非常清楚和直接。如果您是使用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开发人员有所帮助。


7

这是一个简单的规则:

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

到URL的POST应该用于更新或创建位于其他URL(“从属”)的资源,或者不能通过HTTP定位的资源。


1
PUT并非用于更新,而是用于替换,请注意,创建时您不会用任何东西替换任何东西。POST绝对不能以任何形式更新。
thecoshman

2
http规格说明了吗?还是您将评论基于其他内容?
亚当·格里菲思

这只是常识,当您不知道要更新的内容时如何更新?POST用于创建新资源。
thecoshman '16

2
thecoshman-您在这里滥用语义-如果replace是相同的资源,但有一些不同,则可以是更新。仅当使用replace更改同一资源时,replace才对put有效。用新的其他资源替换是无效的(删除旧的并添加新的?),尤其是在“新”资源没有自然ID的情况下。POST,OTOH,是可以创建,更新,替换和删除的东西-使用post取决于是否有消息要解释,例如“套用折扣”,它可能会或可能不会更改资源,具体取决于逻辑。
Gerard ONeill

至于您的第二条评论-您如何“获取”资源,修改所需的字段,然后放回去?或者,如果资源来自其他来源但使用自然ID(外部ID),该情况如何-当原始数据更改时,put会自然地更新URL上的资源。
Gerard ONeill

6

如果您熟悉数据库操作,则有

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

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


5

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


在大多数情况下,从阅读所有这些噪音中,您似乎都可以发挥作用。我要说的是,我们应该将PUT称为replace方法,而不是create / update。我认为它可以更好地描述它的作用。
thecoshman
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.