REST中的PUT与POST

时间:2009-03-10 14:25:20

标签: http rest post put

根据HTTP / 1.1规范:

  

POST 方法用于请求原始服务器接受请求中包含的实体,作为Request-URIRequest-Line标识的资源的新下属{1}}

换句话说,POST用于创建

  

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

也就是说,PUT用于创建或更新

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

35 个答案:

答案 0 :(得分:3900)

总体而言:

PUT和POST都可用于创建。

你必须问“你在做什么动作?”区分你应该使用的东西。我们假设您正在设计一个用于提问的API。如果您想使用POST,那么您可以将其添加到问题列表中。如果你想使用PUT,那么你会对特定问题这样做。

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

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

使用哪种方法取决于您。但请记住使用正确的,具体取决于您在请求中引用的对象。

一些注意事项:

  • 您是否明确指定了您创建的URL对象,还是让服务器决定?如果您为它们命名,则使用PUT。如果您让服务器决定然后使用POST。
  • PUT是幂等的,所以如果你将对象PUT两次,它就没有效果。这是一个很好的属性,所以我会尽可能使用PUT。
  • 您可以使用具有相同对象URL的PUT更新或创建资源
  • 使用POST,您可以在同时修改URL时有2个请求进入,并且可以更新对象的不同部分。

示例:

I wrote the following as part of another answer on SO regarding this

  

发表:

     

用于修改和更新资源

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:

     

用于创建资源,或   覆盖它。当你指定   资源新网址。

     

对于新资源:

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

覆盖现有资源:

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

答案 1 :(得分:2060)

您可以在网上找到说明

的断言

两者都不对。


最好是根据动作的idempotence在PUT和POST之间进行选择。

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

POST 更新资源,添加辅助资源或导致更改。 POST不是幂等的,因为x++不是幂等的。


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

所以:

POST /expense-report

或:

PUT  /expense-report/10929

答案 2 :(得分:647)

  • 发布到网址服务器定义的网址上创建子资源
  • PUT 到网址客户端定义的网址中完整地创建/替换资源
  • PATCH 到该客户定义网址的更新资源的部分

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

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

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

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

PUT 替换已知网址上的资源(如果已存在),因此两次发送相同的请求无效。换句话说,对PUT的调用是幂等的

RFC如下所示:

  

POST和PUT请求之间的根本区别体现在Request-URI的不同含义上。 POST请求中的URI标识将处理所包含实体的资源。该资源可能是数据接受过程,某些其他协议的网关或接受注释的单独实体。相反,PUT请求中的URI标识请求附带的实体 - 用户代理知道URI的用途,服务器不得尝试将请求应用于其他资源。如果服务器希望将请求应用于其他URI,

注意: PUT主要用于更新资源(通过全部替换它们),但最近有使用PATCH更新现有资源的动作,因为PUT指定它替换整个资源资源。 RFC 5789.

更新2018 :有一种情况可以避免PUT。见"REST without PUT"

  

使用“REST without PUT”技术,我们的想法是消费者   被迫发布新的“名词化”请求资源。如上所述   之前,更改客户的邮寄地址是对新邮件的POST   “ChangeOfAddress”资源,而不是具有“客户”资源的PUT   不同的邮寄地址字段值。

取自REST API Design - Resource Modeling by Prakash Subramaniam of Thoughtworks

这会强制API避免多个客户端更新单个资源时的状态转换问题,并且与事件源和CQRS匹配得更好。当工作异步完成时,POST转换并等待它应用似乎是合适的。

答案 3 :(得分:190)

要点:

创建:

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

  

PUT

     

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

PUT /resources/<newResourceId> HTTP/1.1 
     

POST

     

在/ resources URI或集合下创建 A 新资源。通常,服务器返回标识符。

POST /resources HTTP/1.1

更新

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

  

PUT

     

使用 existingResourceId 作为标识符,在/ resources URI或集合下更新资源。

PUT /resources/<existingResourceId> HTTP/1.1

说明:

在处理REST和URI时,您在左侧泛型右侧特定 >。 泛型通常称为集合,更多特定项可称为资源。请注意,资源可以包含集合

  

示例:

     

&lt; - generic-specific - &gt;

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后,您正在引用资源或单个项目,可能在集合中。所以当你说:

PUT /users/john HTTP/1.1

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

规格:

让我重点介绍一下该规范的一些重要部分:

POST

  

POST 方法用于请求原始服务器接受请求中包含的实体 new 从属< / strong>请求行中的Request-URI标识的资源

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

PUT

  

PUT 方法请求所提供的Request-URI下包含的实体存储。如果Request-URI引用已存在的资源,则所包含的实体应该被视为驻留在源服务器上的修改版本。如果Request-URI 未指向现有资源,并且该能力被定义为 资源< / strong>通过请求用户代理,源服务器可以创建具有该URI的资源。“

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

参考:

答案 4 :(得分:169)

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

答案 5 :(得分:162)

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

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

您发布到example.com/users,因为您还不知道用户的URL,您希望服务器创建它。

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

使用相同数据发布两次意味着创建两个具有不同ID的相同用户。使用相同数据进行两次输入会创建第一个用户,并在第二次将其更新为相同状态(无更改)。既然你的PUT后相同的状态结束了,不管你有多少次执行它,它被说成是“同等有效”每一次 - 幂等。这对于自动重试请求很有用。当您按下浏览器上的后退按钮时,不再“您确定要重新发送”。

一般建议是在需要服务器控制资源的URL生成时使用POST。否则使用PUT。首选PUT over POST。

答案 6 :(得分:121)

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

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

答案 7 :(得分:92)

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

Enter image description here

类比:

  • PUT即拿走放在原处。
  • 帖子办公室发送邮件作为发送邮件。

enter image description here

社交媒体/网络类比:

    社交媒体上的
  • 发布:当我们发布消息时,它会创建新帖子。
  • 点击(即编辑)我们已发布的消息。

答案 8 :(得分:65)

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

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

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

这就是AtomPub关于资源创建的说法(第9.2节):

  

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

答案 9 :(得分:58)

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

此时有人会争辩说,如果使用 RESTful-URL&#39> ,客户​​端确实知道资源的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. 客户端将新资源POST到服务器。
  2. 服务器处理请求并发送响应。
  3. 客户端从未收到回复。
  4. 服务器未发现客户端未收到响应。
  5. 客户端没有资源的URL(因此PUT不是一个选项)并重复POST。
  6. POST不是幂等的服务器......
  7. 第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,并在Section 4.3.3中描述了以下可能的POST响应

      

    如果处理POST的结果等于a   现有资源的表示,原始服务器可以重定向   通过发送303(请参阅其他)响应来访问该资源的用户代理   使用位置字段中的现有资源标识符。这个   具有为用户代理提供资源标识符的好处   并通过更适合的方法转移表示   共享缓存,但是以用户的额外请求为代价   代理程序尚未缓存表示。

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

    有关此内容的详细信息,请阅读此article

答案 10 :(得分:52)

我喜欢这个建议,来自RFC 2616's definition of PUT

  

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

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

我将此解释,以及对PUT的幂等性要求意味着:

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

答案 11 :(得分:45)

简而言之:

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

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

与数据库查询类比

PUT 你可以想到类似于&#34; UPDATE STUDENT SET地址=&#34; abc&#34;其中id =&#34; 123&#34 ;;

POST 你可以想到像&#34; INSERT INTO STUDENT(姓名,地址)价值观(&#34; abc&#34;,&#34; xyzzz&#34;);

学生ID是自动生成的。

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

在POST的情况下,如果多次执行相同的查询,则在数据库中创建多个学生记录,并且每次执行&#34; INSERT&#34;查询。

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

有些人可能会想到可以使用POST执行更新。没有硬性规则可以用于更新,也可以用于创建。这些都是惯例,直观地说,我倾向于上述推理并遵循它。

答案 12 :(得分:42)

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

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

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

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

POST versus PUT

答案 13 :(得分:38)

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

PUT仅仅是服务应该从现在开始用于呈现客户端识别的资源的表示的内容的声明; POST是一个声明,说明服务从现在开始应该包含哪些内容(可能是重复的),但服务器应该如何识别该内容。

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

PUT x(如果x无法识别资源):“创建包含我的内容的新资源,并使用x来识别它。”

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

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

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

PUT /something(如果/something已经存在):“在/something取你所拥有的一切,并用我给你的东西取而代之。”

PUT /something(如果/something尚不存在):“拿我给你的东西并把它放在/something。”

POST /something:“只要你在完成后给我的网址,就把我给你的东西放在/something下的任意位置。”

答案 14 :(得分:36)

简答:

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

长答案:

POST:

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

PUT:

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

更长的答案:

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

从REST架构的角度来看,没有一件事重要。我们本可以没有PUT生活。但是从客户端开发人员的角度来看,这使他/她的生活变得更加简单。

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

答案 15 :(得分:35)

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

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

  

需要一种新方法来提高互操作性并防止出现这种情况      错误。 PUT方法已定义为覆盖资源      具有完整的新体,并且不能重复使用来进行部分更改。      否则,代理和缓存,甚至客户端和服务器都可能获得      混淆了操作的结果。 POST已被使用但是      没有广泛的互操作性(对于一个,没有标准的方法      发现补丁格式支持)。早期的HTTP中提到了PATCH      规格,但没有完全定义。

Edge Rails: PATCH is the new primary HTTP method for updates”解释了它。

答案 16 :(得分:26)

冒着重述已经说过的风险,重要的是要记住 PUT 意味着客户端控制 URL 最终将会是什么,在创建资源时。因此, PUT POST 之间的部分选择将取决于您可以信任客户端提供正确的,规范化的 URL 的程度。与您的URL方案一致。

如果你不能完全信任客户做正确的事,那就是 更适合使用 POST 创建新项目,然后在回复中将URL发送回客户端。

答案 17 :(得分:21)

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

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

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

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

在一行中,使用 POST 在数据库中添加新条目,并将 PUT 添加到更新数据库中的东西。

答案 18 :(得分:20)

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

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

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

其他一些注意事项:

  • POST使整个包含资源的缓存副本无效(更好的一致性)
  • PUT响应不可缓存,而POST则是(需要内容 - 位置和到期)
  • PUT受到例如支持Java ME,旧版浏览器,防火墙

答案 19 :(得分:14)

对于这个主题的新读者将会被关于你应该做什么的无休止的讨论以及相对缺乏经验教训所震惊。我认为,REST比SOAP更“优先”的事实是从经验中获得高水平的学习,但我们必须从那里取得进步吗?这是2016年。罗伊的论文是在2000年。我们开发了什么?它有趣吗?是否易于集成?支持?它会处理智能手机和移动连接的崛起吗?

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

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

或者您可以这样做:将您的不安全请求视为短暂的单用户资源(让我们称之为动作)。客户端在实体资源上请求新的“操作”,对资源进行空POST。 POST将仅用于此目的。一旦安全地拥有新鲜动作的URI,客户端就会将不安全的请求发送到动作URI,而不是目标资源。解决操作和更新“真实”资源恰好是API的工作,并且在这里与不可靠的网络分离。

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

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

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

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

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

在告诉我这不是RESTful之前,请考虑REST原则受到尊重的众多方式。客户端不构造URL。虽然语义上有一点变化,但API仍然是可发现的。适当使用HTTP谓词。如果你认为这是一个巨大的改变,我可以从经验告诉你,它不是。

如果您认为要存储大量数据,那就让我们谈谈数量:典型的更新确认只是一个千字节的一小部分。 HTTP目前为您提供一两分钟的明确回应。即使您只存储一周的行动,客户也有足够的机会赶上。如果您的数量非常大,您可能需要一个专用的符合酸的键值存储或内存解决方案。

答案 20 :(得分:14)

对于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(更新)操作。在某些情况下,可以将PUT用于创建,而在其他情况下,则需要POST。模糊性在于HTTP PUT方法与HTTP POST方法的定义。

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

基于上面的幂等定义,我使用HTTP PUT方法而不是使用HTTP POST方法来实现REST服务是: 在以下情况下使用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方法。

答案 21 :(得分:13)

  

源服务器可以使用该URI

创建资源

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

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

答案 22 :(得分:11)

我将以下列内容登陆:

PUT是指由URI标识的资源。在这种情况下,您正在更新它。它是三个动词中引用资源的一部分 - 删除并成为另外两个。

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


因为PUT和GET和DELETE引用了一个资源,所以它们也是幂等的。

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

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


编辑:还有一件事 - PUT可以创建,但如果确实如此,则ID必须是自然ID - AKA是电子邮件地址。那样当你PUT两次时,第二次put是对第一次的更新。这使得幂等

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

答案 23 :(得分:11)

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

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

答案 24 :(得分:9)

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

我将描述我认为最常用且最有用的惯例:

当您在特定网址上投放资源时,会发生的事情是它应该保存在该网址上,或者沿着这些网址保存。

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

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

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

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

答案 25 :(得分: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用于更新没有争议。

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

答案 26 :(得分:7)

大多数情况下,你会像这样使用它们:

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

例如:

  • 发布 / items
  • PUT / items / 1234

在这两种情况下,请求正文都包含要创建或更新的资源的数据。从路由名称中可以明显看出POST不是幂等的(如果你调用它3次就会产生3个对象),但PUT是幂等的(如果你称之为3次,结果是相同的)。 PUT通常用于&#34; upsert&#34;操作(创建或更新),但如果您只想使用它来修改,则总是可以返回404错误。

请注意POST&#34;创建&#34;集合中的一个新元素,PUT&#34;取代&#34;在给定URL处的元素,但是使用PUT进行部分修改是非常常见的做法,即,仅将其用于更新现有资源并仅修改正文中包含的字段(忽略其他字段)。这在技术上是不正确的,如果你想要REST-purist,PUT应该替换整个资源,你应该使用PATCH进行部分更新。就个人所有API端点的行为清晰且一致而言,我个人并不在乎。

请记住,REST是一组保持API简单的约定和指南。如果你最终得到一个复杂的解决办法,只需检查&#34; RESTfull&#34;那么你正在击败目的;)

答案 27 :(得分:6)

这是一个简单的规则:

应该使用

PUT 来更新或创建可以位于该URL的资源。

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

答案 28 :(得分:6)

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

  1. 选择
  2. 插入
  3. 更新
  4. 删除
  5. 合并(如果已存在则更新,否则插入)
  6. 我使用PUT进行合并并更新操作,并使用POST进行插入。

答案 29 :(得分:5)

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

答案 30 :(得分:3)

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

  

POST也用于更新记录。

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

  

PUT也用于更新资源

答案 31 :(得分:2)

  

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

您应该使用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是恕我直言唯一正确的选择,其他一切都是圆孔中的方形钉。不幸的是,我们所有的都是圆孔。

答案 32 :(得分:0)

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

如果您想要一个没有JavaScript的Web应用程序(例如,如果有人使用命令行浏览器(例如Lynx)或浏览器插件(例如NoScript或uMatrix)),则自HTML以来,您将必须使用POST发送数据表单仅支持GET和POST HTTP请求。

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

答案 33 :(得分:0)

以上所有答案的补充:


在专业实践中最常用的


  • 我们在 CREATE 操作中通过POST使用PUT。为什么?因为这里的许多人也说过,而POST响应(要求Content-Location和到期)则响应是不可缓存的。
  • 我们在 UPDATE 操作中使用POST over PUT。为什么?因为它会使整个包含资源的缓存副本无效。这在更新资源时很有帮助。

答案 34 :(得分:0)

GET,PUT和DELETE的请求方法是CRUD(创建,读取,更新和删除)操作(即数据管理操作),是对 target 资源(状态为由请求URI标识的一个):

  • GET应该读取目标资源的状态; <​​/ li>
  • PUT应该创建更新目标资源的状态; <​​/ li>
  • 删除应删除目标资源的状态。

请求方法POST是另一种野兽。它不应创建像PUT这样的目标资源的状态,因为它是 process 操作,其目标级别比CRUD高(参见RFC 7231, § 4.3.3)。进程可以创建资源,但与 target 资源不同,否则应使用较低级别的目标请求方法PUT,因此即使在这种情况下也不能这样做CRUD操作。

CRUD操作(HTTP中的GET,PUT和DELETE)和非CRUD操作(HTTP中的POST)之间的区别是抽象数据类型对象之间的区别艾伦·凯(Alan Kay)在大部分演讲和他的ACM论文The Early History of Smalltalk中都强调:

我从Simula那里得到的是,您现在可以用目标替换绑定和分配。您希望任何程序员做的最后一件事就是弄乱内部状态,即使以图形方式呈现也是如此。相反,应该将对象呈现为更适合用作动态组件的更高级别行为的站点。

[…]不幸的是,当今所谓的“面向对象程序设计”中的许多内容只是带有高级构造的旧式程序设计。许多程序现在都通过“昂贵的附加程序”来完成“分配样式”操作。

[…]分配语句(甚至是抽象的)也表达了非常低级的目标,需要更多的目标才能完成任务。 […]可以考虑所有这一切的另一种方式是:尽管自动存储分配的后期绑定无法完成程序员无法做的任何事情,但它的存在会导致更简单,更强大的代码。 OOP是许多事物的后期绑定策略,与旧方法相比,它们将延缓脆弱性和规模爆炸的时间更长。