关于http:PUT与REST中的POST

PUT vs. POST in REST

根据HTTP/1.1的规格:

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line

换句话说,POST是创建。

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI."

这是PUT,是创建或更新。

因此,它应该被用来创建一个资源?或是一个需要支持?


总体:

Put和Post都可以用于创建。

你必须问"你在做什么?"区分你应该使用什么。假设您正在设计一个用于提问的API。如果你想用post,你可以把它放到一个问题列表上。如果你想使用Put,那么你可以对一个特定的问题这样做。

两者都很好,所以我应该在我的休息设计中使用哪一个:

您不需要同时支持Put和Post。

用过的就交给你了。但是记住要根据您在请求中引用的对象使用正确的对象。

一些注意事项:

  • 您是显式命名您创建的URL对象,还是由服务器决定?如果你说出他们的名字,那就用put。如果您让服务器决定,那么使用POST。
  • Put是等幂的,所以如果你把一个对象放两次,它就没有效果。这是一个很好的财产,所以我会尽可能使用看跌期权。
  • 可以使用具有相同对象URL的Put更新或创建资源
  • 使用Post,您可以同时收到2个请求,对一个URL进行修改,它们可能会更新对象的不同部分。

一个例子:

关于这一点,我在另一份答复中写道:

POST:

Used to modify and update a resource

1
2
POST /questions/<existing_question> HTTP/1.1
Host: www.example.com/

Note that the following is an error:

1
2
POST /questions/<new_question> HTTP/1.1
Host: www.example.com/

If the URL is not yet created, you
should not be using POST to create it
while specifying the name. This should
result in a 'resource not found' error
because does not exist
yet. You should PUT the
resource on the server first.

You could though do something like
this to create a resources using POST:

1
2
POST /questions HTTP/1.1
Host: www.example.com/

Note that in this case the resource
name is not specified, the new objects
URL path would be returned to you.

PUT:

Used to create a resource, or
overwrite it. While you specify the
resources new URL.

For a new resource:

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

To overwrite an existing resource:

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


你可以在网上找到这样的断言

  • post用于创建资源,put用于修改资源
  • put用于创建资源,post用于修改资源

两者都不完全正确。

更好的方法是根据动作的等幂性在Put和Post之间进行选择。

Put意味着放置一个资源-用一个不同的东西完全替换给定URL上的可用资源。根据定义,看跌期权是等量的。你想做多少次就做多少次,结果是一样的。x=5是等幂的。您可以放置一个资源,不管它以前是否存在(例如,创建或更新)!

post更新资源、添加辅助资源或导致更改。post不是等幂的,就像x++不是等幂的。

通过这个参数,put用于在知道要创建的对象的URL时创建。当您知道"工厂"的URL或要创建的类别的管理器时,可以使用Post来创建。

所以:

1
POST /expense-report

或:

1
PUT  /expense-report/10929


  • 发布到URL在服务器定义的URL上创建子资源。
  • 放到一个URL,在客户端定义的URL上创建/替换整个资源。
  • 对URL的修补将更新该客户机定义的URL处的部分资源。

Put和Post的相关规范为RFC 2616§9.5ff。

post创建一个子资源,所以post to /items创建一个位于/items资源下的资源。如/items/1。两次发送相同的邮包将创建两个资源。

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

因此:put只是一个候选的create,客户机在创建资源之前就已经知道该URL。例如,使用/blogs/nigel/entry/when_to_use_post_vs_put作为标题作为资源键

如果已知的URL已经存在,则PUT将替换该资源,因此两次发送相同的请求没有任何效果。换句话说,put的调用是等幂的。

RFC如下所示:

The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI,

注意:Put主要用于更新资源(通过在其实体中替换资源),但最近出现了使用修补程序更新现有资源的趋势,因为Put指定它将替换整个资源。RFC 5789。

更新2018:有一个案例可以避免放置。见"无投入休息"

With"REST without PUT" technique, the idea is that consumers are
forced to post new 'nounified' request resources. As discussed
earlier, changing a customer’s mailing address is a POST to a new
"ChangeOfAddress" resource, not a PUT of a"Customer" resource with a
different mailing address field value.

摘自RESTAPI设计-由Prakash Subramaniam设计的ThoughtWorks资源建模

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


总结:创建:

可以通过以下方式执行Put或Post:

PUT

Creates THE new resource with newResourceId as the identifier, under the /resources URI, or collection.

1
PUT /resources/<newResourceId> HTTP/1.1

POST

Creates A new resource under the /resources URI, or collection. Usually the identifier is returned by the server.

1
POST /resources HTTP/1.1

更新:

只能通过以下方式执行Put:

PUT

Updates the resource with existingResourceId as the identifier, under the /resources URI, or collection.

1
PUT /resources/<existingResourceId> HTTP/1.1

说明:

当将rest和uri作为常规处理时,左边是泛型,右边是特定的。泛型通常称为集合,更具体的项可以称为资源。请注意,资源可以包含集合。

Examples:

<-- generic -- specific -->

1
2
3
4
5
6
7
8
9
10
11
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时,你总是引用一个集合,所以每当你说:

1
POST /users HTTP/1.1

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

如果你继续这样做:

1
POST /users/john HTTP/1.1

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

一旦使用了Put,您将引用一个资源或单个项,可能是在集合中。所以当你说:

1
PUT /users/john HTTP/1.1

您正在通知服务器更新,或者在不存在的情况下创建用户集合下的john资源。

Spec:

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

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line

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

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI."

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

参考文献:

  • HTTP/1.1规格
  • 维基百科-休息
  • 统一资源标识符(URI):通用语法和语义


我想补充一下我的"务实"建议。当您知道可以通过"id"来检索要保存的对象时,可以使用put。如果您需要(比如说)返回数据库生成的ID以便将来进行查找或更新,那么使用Put就不会太好地工作。

所以:要保存现有用户,或者客户机在其中生成ID并已验证该ID是唯一的用户,请执行以下操作:

1
2
3
4
5
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最初创建对象,并放置以更新对象:

1
2
3
4
5
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


post的意思是"创建新的",正如"这里是创建用户的输入,为我创建"。

Put表示"插入,如果已经存在则替换",如"这里是用户5的数据"。

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

由于要替换/创建特定用户,所以将其放置到example.com/users/id。

使用相同数据发布两次意味着创建两个具有不同ID的相同用户。使用相同的数据输入两次将创建第一个用户,并在第二次将其更新为相同的状态(无更改)。因为不管你做了多少次Put,结果都是相同的状态,所以每次都被称为"同等效力"——等量。这对于自动重试请求很有用。当您按下浏览器上的后退按钮时,不再显示"确定要重新发送吗"。

一般的建议是在需要服务器控制资源的URL生成时使用POST。否则使用Put。宁愿放在岗位上。


使用post来创建和放置以更新。无论如何,RubyonRails就是这样做的。

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


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

Enter image description here

类比:

  • 放,也就是说,拿着放在原来的地方。
  • 在邮局以寄信方式邮寄。

enter image description here

社交媒体/网络类比:

  • 在社交媒体上发布:当我们发布消息时,它会创建新的帖子。
  • 对我们已经发布的消息进行编辑。


休息是一个非常高层次的概念。实际上,它甚至根本没有提到HTTP!

如果您对如何在HTTP中实现REST有任何疑问,可以随时查看Atom发布协议(atompub)规范。Atompub是用HTTP编写RESTful Webservices的标准,它是由许多HTTP和REST照明器开发的,其中一些输入来自于REST的发明者和HTTP自己的(共同)发明者Roy Fielding。

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

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

To add members to a Collection, clients send POST requests to the URI of the Collection.


是否使用Put或Post在具有HTTP+RESTAPI的服务器上创建资源的决定取决于谁拥有URL结构。让客户机知道或者参与定义,URL结构是一个不必要的耦合,类似于SOA产生的不需要的耦合。逸出的耦合类型是REST如此流行的原因。因此,正确的使用方法是post。此规则存在例外情况,当客户端希望保留对其部署的资源的位置结构的控制时,就会出现例外情况。这是罕见的,可能意味着有其他问题。

此时,有些人会争辩说,如果使用RESTful URL,客户机确实知道资源的URL,因此Put是可以接受的。毕竟,这就是为什么规范化、规范化、RubyonRails、DjangoURL很重要,看看TwitterAPI…废话废话。这些人需要明白,没有一个宁静的网址,罗伊·菲尔丁自己说:

A REST API must not define fixed resource names or hierarchies (an
obvious coupling of client and server). Servers must have the freedom
to control their own namespace. Instead, allow servers to instruct
clients on how to construct appropriate URIs, such as is done in HTML
forms and URI templates, by defining those instructions within media
types and link relations. [Failure here implies that clients are
assuming a resource structure due to out-of band information, such as
a domain-specific standard, which is the data-oriented equivalent to
RPC's functional coupling].

REST APIs must be hypertext-driven

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

使用post来创建资源需要设计考虑,因为post不是等幂的。这意味着重复几次发帖并不能保证每次都有相同的行为。这让人们害怕在不应该使用投入物来创造资源。他们知道这是错误的(post是用来创建的),但他们还是这么做了,因为他们不知道如何解决这个问题。在以下情况下可以证明这一问题:

  • 客户端将新资源发布到服务器。
  • 服务器处理请求并发送响应。
  • 客户机从未收到响应。
  • 服务器不知道客户端没有收到响应。
  • 客户端没有资源的URL(因此Put不是一个选项),并重复发布。
  • post不是等幂的,服务器…
  • 第6步是人们通常对该做什么感到困惑的地方。但是,没有理由创建一个Kludge来解决这个问题。相反,可以按照RFC2616中的规定使用HTTP,并且服务器响应:

    10.4.10 409 Conflict

    The request could not be completed due to a conflict with the current
    state of the resource. This code is only allowed in situations where
    it is expected that the user might be able to resolve the conflict and
    resubmit the request. The response body SHOULD include enough

    information for the user to recognize the source of the conflict.
    Ideally, the response entity would include enough information for the
    user or user agent to fix the problem; however, that might not be
    possible and is not required.

    Conflicts are most likely to occur in response to a PUT request. For
    example, if versioning were being used and the entity being PUT
    included changes to a resource which conflict with those made by an
    earlier (third-party) request, the server might use the 409 response
    to indicate that it can’t complete the request. In this case, the
    response entity would likely contain a list of the differences between
    the two versions in a format defined by the response Content-Type.

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

    • 执行具有与系统中已有资源匹配的ID的数据发布是"与资源的当前状态冲突"。
    • 因为重要的部分是让客户机了解服务器拥有资源并采取适当的行动。这是一种"期望用户能够解决冲突并重新提交请求的情况"。
    • 包含具有冲突ID的资源的URL和资源的适当前提条件的响应将"为用户或用户代理提供足够的信息来解决问题",这是RFC2616的理想情况。

    基于发布的RFC7231更新以替换2616

    RFC7231设计用于替换2616,在第4.3.3节中,描述了一个岗位的以下可能响应

    If the result of processing a POST would be equivalent to a
    representation of an existing resource, an origin server MAY redirect
    the user agent to that resource by sending a 303 (See Other) response
    with the existing resource's identifier in the Location field. This
    has the benefits of providing the user agent a resource identifier
    and transferring the representation via a method more amenable to
    shared caching, though at the cost of an extra request if the user
    agent does not already have the representation cached.

    如果一个帖子被重复发布,那么现在只需返回303就可以了。然而,事实恰恰相反。只有当多个创建请求(创建不同的资源)返回相同的内容时,返回303才有意义。例如,"感谢您提交请求消息",客户机不需要每次重新下载。RFC7231在第4.2.2节中仍然坚持认为post不等幂,并继续坚持认为post应该用于创建。

    有关这方面的更多信息,请阅读本文。


    我喜欢这个建议,来自于RFC2616对Put的定义:

    The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource.

    这个jibes和这里的其他建议,即put最好应用于已经有名称的资源,post对于在现有资源下创建一个新对象(并让服务器命名它)是很好的。

    我解释这一点,以及Put的等幂性要求,意思是:

    • post适合在集合下创建新对象(并且create不需要等幂)
    • Put适合于更新现有对象(并且更新需要是等幂的)
    • post还可以用于对现有对象的非等幂更新(尤其是,在不指定整个对象的情况下更改对象的一部分--如果您考虑它,从集合的角度来看,创建集合的新成员实际上是此类更新的一种特殊情况)。
    • 如果并且仅当您允许客户机命名资源时,Put还可以用于创建。但是,由于REST客户机不应该对URL结构进行假设,所以这并不是有意的。


    短:P></

    我是幂等的,那里的资源被will be the same the operation is if the same time或多个executed时报。P></

    后非幂等where is the资源已经成为可能,多executed if the operation is different as to compared单身时代执行的时间。P></类比与数据库查询

    of similar to put你可以认为"学生集更新地址="abc";where id ="123"P></

    你可以认为of something like后"insert into学生(名称,地址)values("ABC"、"xyzzz");P></

    学生id is generated汽车。P></

    与if the same is put,查询或一次性多executed时代,学生保持了the same the table。P></

    学院在房屋后,if the same查询学生时代那么多的多executed is created in the数据库记录get and the changes of each执行在线数据库被安"insert"查询。P></

    注释:把需要的资源(资源已经由which needs to update)发生后,不whereas require that。therefore is for的意思后intuitively creation of New whereas is needed for资源,把现有资源already the 12。P></

    五月,以作为后续with some Performed can be with。不规则which there is one to硬盘使用for which one to or for以创建使用。再次,这些是和我的约定,intuitively倾向与上述推理和跟踪它。P></


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

    通过Post,您可以将邮件发送到队列或集合的地址。使用Put时,您将输入项目的地址。

    Put是等幂的。你可以发送100次请求,这无关紧要。post不是等幂的。如果你发送100次请求,你会收到100封电子邮件或100封信在你的邮箱。

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

    POST versus PUT


    新答案(现在我更好地理解了休息):

    Put只是一个声明,说明从现在开始,服务应该使用什么内容来呈现客户机标识的资源的表示;Post是一个声明,说明从现在开始,服务应该包含什么内容(可能是重复的),但如何标识该内容取决于服务器。

    PUT x(如果x标识一个资源):"用我的内容替换x标识的资源的内容。"

    PUT x(如果x未标识资源):"创建包含我的内容的新资源,并使用x标识它。"

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

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

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

    PUT /something(如果/something已经存在):"把你在/something拥有的东西拿走,换成我给你的东西。"

    PUT /something(如果/something还不存在):"拿我给你的,放在/something上。"

    POST /something说:"把我给你的东西拿出来,放在你想放在/something下的任何地方,只要你写完后给我它的网址。"


    简短回答:

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

    长回答:

    职位:

    • post用于将数据发送到服务器。
    • 当资源的URL为未知的

    放置:

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

    更长的答案:

    为了理解这一点,我们需要质疑为什么需要放置,放置的问题是什么,试图解决那个帖子不能。

    从REST架构的角度来看,没有什么是重要的。我们也可以没有普特的生活。但从客户开发人员的角度来看,这让他/她的生活简单多了。

    在Put之前,客户机不能直接知道服务器生成的URL,也不能直接知道服务器生成的所有URL是否都生成了任何URL,或者要发送到服务器的数据是否已经更新。舒缓了发展商的所有头痛。Put是等幂的,Put处理竞态条件,Put让客户机选择URL。


    RubyonRails4.0将使用"patch"方法而不是put来进行部分更新。

    RFC5789提到补丁(从1995年开始):

    A new method is necessary to improve interoperability and prevent
    errors. The PUT method is already defined to overwrite a resource
    with a complete new body, and cannot be reused to do partial changes.
    Otherwise, proxies and caches, and even clients and servers, may get
    confused as to the result of the operation. POST is already used but
    without broad interoperability (for one, there is no standard way to
    discover patch format support). PATCH was mentioned in earlier HTTP
    specifications, but not completely defined.

    "Edge Rails:Patch是用于更新的新的主要HTTP方法",对此进行了解释。


    在重述已经说过的内容的风险下,重要的是要记住,put意味着客户端在创建资源时控制URL的最终内容。因此,在Put和Post之间选择的一部分是,您可以信任客户机提供与您的URL方案一致的正确、规范化的URL。

    当你不能完全信任客户做正确的事情时,那就是更适合使用post创建新项目,然后在响应中将URL发送回客户机。


    在我以很简单的方式the example of the Facebook的时间轴。P></

    1:当你的房子后,你的在线时间的东西,这是一种新的后起之秀。我知道他们在这房子后,因为使用方法method is the后非幂等。P></

    2:如果你的朋友的房子后第一时间在线评论你的茶,那也将设立在输入数据库后,我在the method used。P></

    3:如果你的朋友的房子edits他的评论,在这有房子,他们知道他们会在评论ID更新,instead of an existing Comment creating the New进入数据库。therefore for this type of operation method is put the因为它使用*幂等。P></

    在单一网络后,使用to add a new entry to put in the数据库和更新数据库中的一些茶。P></


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

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

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

    其他注意事项:

    • post使整个包含资源的缓存副本失效(更好的一致性)
    • 发布响应时,放置响应不可缓存(需要内容位置和过期)
    • JavaME、旧浏览器、防火墙不太支持PoT


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

    1
    2
    3
    4
    Create => HTTP PUT
    Retrieve => HTTP GET
    Update => HTTP POST
    Delete => HTTP DELETE

    确实,CRUD操作的r(etrieve)和d(elete)可以分别直接映射到HTTP方法get和d elete。然而,混淆在于C(reate)和U(update)操作。在某些情况下,可以使用Put进行创建,而在其他情况下则需要发布。这种模糊性在于HTTP PUT方法相对于HTTP POST方法的定义。

    根据HTTP1.1规范,get、head、delete和put方法必须是等幂的,post方法不是等幂的。也就是说,如果一个操作可以在一个资源上执行一次或多次,并且总是返回该资源的相同状态,那么它就是等量的。而非等幂运算可以将修改后的资源状态从一个请求返回到另一个请求。因此,在一个非等幂运算中,不能保证一个人将获得相同的资源状态。

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

    1
    2
    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方法:

    1
    2
    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方法。


    对这个话题不熟悉的读者会被没完没了的关于你应该做什么的讨论和经验教训的相对缺失所震惊。我想,休息比肥皂更"受欢迎"的事实是,从经验中获得了高层次的学习,但我们必须从中取得进展?它是2016。罗伊的论文发表于2000年。我们开发了什么?有趣吗?集成起来容易吗?支持?它能应对智能手机和脆弱的移动连接的崛起吗?好的。

    我认为现实生活中的网络是不可靠的。请求超时。连接被重置。网络一次中断数小时或数天。火车进入隧道,车上有移动用户。对于任何给定的请求(在所有讨论中偶尔会承认),请求可能会在其返回的过程中掉入水中,或者响应可能在其返回的过程中掉入水中。在这种情况下,直接针对实质性资源发布Put、Post和Delete请求,我总是觉得有点残忍和幼稚。好的。

    HTTP无法确保请求响应的可靠完成,这很好,因为这正是网络感知应用程序的工作。开发这样一个应用程序,您可以跳过Hoops来使用Put而不是Post,如果您检测到重复的请求,那么可以使用更多的Hoops来在服务器上产生某种错误。回到客户机上,然后您必须跳过去解释这些错误,重新蚀刻,重新验证和重新发布。好的。

    或者您可以这样做:将不安全的请求视为短暂的单用户资源(让我们称之为操作)。客户机请求对实质性资源执行新的"操作",对该资源执行空的日志。Post将仅用于此。一旦安全地拥有新生成的操作的URI,客户机就将不安全的请求放在操作URI上,而不是目标资源上。解决这个操作并更新"真正的"资源是您的API的工作,并且在这里脱离了不可靠的网络。好的。

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

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

    最重要的是,我们让发送和接收应用程序有机会将唯一标识的操作链接到各自环境中的唯一性。我们可以开始要求和执行!,来自客户的负责任的行为:尽可能重复您的请求,但在您掌握现有请求的最终结果之前,不要生成新的操作。好的。

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

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

    在告诉我这不是休息之前,请考虑到休息原则被尊重的许多方式。客户端不构造URL。API保持可发现性,尽管语义上略有变化。正确使用HTTP动词。如果你认为这是一个需要实施的巨大变革,我可以从经验中告诉你,事实并非如此。好的。

    如果您认为您将有大量的数据要存储,那么让我们来谈谈容量:典型的更新确认是千字节的一小部分。HTTP目前为您提供一到两分钟的时间来做出明确的响应。即使你只存储一周的行为,客户也有足够的机会赶上。如果您的容量非常大,您可能需要一个专用的符合ACID的键值存储,或者一个内存中的解决方案。好的。好啊。


    the origin server can create the resource with that URI

    所以你使用post,可能,但不是创建资源所必需的put。你不需要两者都支持。对我来说,这个职位已经足够了。所以这是一个设计决策。

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


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

    在post方法中,您可以在form-data中发送body参数。

    在put方法中,您必须在x-www-form-urlencoded中发送body参数。

    割台Content-Type:application/x-www-form-urlencoded

    因此,在put方法中不能发送文件或多部分数据。

    编辑

    The content type"application/x-www-form-urlencoded" is inefficient
    for sending large quantities of binary data or text containing
    non-ASCII characters. The content type"multipart/form-data" should be
    used for submitting forms that contain files, non-ASCII data, and
    binary data.

    这意味着如果你必须提交

    files, non-ASCII data, and binary data

    你应该使用post方法


    我将用以下方法着陆:

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

    post基本上是一个自由形式的消息,其含义是"带外"。如果可以将消息解释为向目录中添加资源,那就可以了,但基本上您需要了解正在发送(发布)的消息,以了解资源将发生什么。

    因为put、get和delete引用的是一个资源,所以它们也是按定义等幂的。

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

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

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

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


    语义应该是不同的,因为"put"和"get"应该是等幂的,也就是说,您可以多次执行相同的精确put请求,结果就像只执行一次一样。

    我将描述我认为最广泛使用和最有用的惯例:

    当您将一个资源放到一个特定的URL上时,会发生的情况是它应该保存在该URL上,或者沿着这些行保存一些内容。

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

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

    至于修改流的属性,可以使用Put或Post来完成。基本上,只有当操作为等幂时才使用"put",否则使用post。

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


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

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

    1
    2
    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是用于更新的,没有争论。

    我希望这有助于任何微软开发人员阅读所有评论与亚马逊和Sun/Java网站链接。


    You will most of them the time,这样使用:P></

    • 进入后在资源收集
    • 在资源采集/放模式:identified ID

    for example:P></

    • 后/ items
    • items/把/1234

    在两例,contains the the request for the body to be created日期或最新资源。恩-- should be from the names that is not幂等路线后(如果你呼叫它将创建的对象3时报/ 3),but is put幂等的(如果你呼叫它the result is the same 3时报)。把"upsert is often used for operation"(创建或更新),但你可以总是返回404错误,如果你只想使用it to modify。P></

    注释"创源后,在"元"replaces the collection,把"安元(given URL,但它是很常见的做法使用put to that is for部分modifications,only to update,利用现有资源和EN modify the included in the only体字段(字段ignoring the other)。technically this is incorrect休息好,如果你想把你purist should replace the Whole资源,你应该使用补丁for the部分更新。亲爱的别让我personally is as clear as the行为的API和你洽在端点。P></

    记住,你的目的是让学院的约定和集到你的简单的API。如果你端上与周围的复杂工件的只是"to check restfull"那么你是defeating茶盒)的目的;P></


    下面是一个简单的规则:

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

    发布到URL应用于更新或创建位于其他("从属")URL或不可通过HTTP定位的资源。


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

  • 选择
  • 插入
  • 更新
  • 删除
  • 合并(如果已存在则更新,否则插入)
  • 我使用PUT进行类似合并和更新的操作,使用POST进行插入。


    在实践中,post在创建资源方面工作得很好。应在位置响应头中返回新创建资源的URL。Put应用于完全更新资源。请理解,这些是设计RESTfulAPI时的最佳实践。这样的HTTP规范并没有限制在创建/更新资源时使用Put/Post,而是有一些限制。请访问http://techoctave.com/c7/posts/71-twitter-rest-api-dissected,了解最佳实践。


    发布:使用它来创建新资源。它类似于具有自动递增ID的插入(SQL语句)。在响应部分,它包含新生成的ID。

    POST is also used for updating a record.

    放置:使用它来创建一个新资源,但是这里我知道身份密钥。这就像插入(SQL语句)一样,我提前知道了标识键。在响应部分,它什么也不发送。

    PUT is also used for updating a resource


    So, which one should be used to create a resource? Or one needs to support both?

    你应该使用PATCH。你在问题列表上打补丁,比如

    1
    PATCH /questions HTTP/1.1

    包含要创建的对象的列表

    1
    2
    3
    4
    5
    6
    7
    [
        {
           "title":"I said semantics!",
           "content":"Is this serious?",
           "answer":"Not really"
        }
    ]

    这是一个补丁请求

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

    此方法的一个巨大优势是,您可以使用单个请求创建多个实体,只需在列表中提供所有实体即可。

    这显然是PUT所不能做的。您可以使用POST创建多个实体,因为它是HTTP的厨房水槽,基本上可以做任何事情。

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

    您可以使用CREATE来代替,因为允许自定义HTTP动词,只是它们可能无法与某些工具一起使用。

    在语义学方面,CREATE是唯一正确的选择,其他的都是一个方钉在圆孔里。不幸的是,我们只有圆孔。