HTTP中的POST和PUT有什么区别?

问题描述:

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

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

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

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

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

解决方案1:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

全面的:

PUT 和 POST 都可用于创建。

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

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

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

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

一些考虑:

您是明确命名您创建的 URL 对象,还是让服务器决定?如果您命名它们,则使用 PUT。如果您让服务器决定然后使用 POST。

PUT 被定义为假定幂等性,所以如果你 PUT 一个对象两次,它应该没有额外的效果。这是一个不错的属性,所以我会尽可能使用 PUT。只需确保 PUT 幂等性实际上在服务器中正确实现。

您可以使用具有相同对象 URL 的 PUT 更新或创建资源

使用 POST,您可以同时收到 2 个请求来修改 URL,它们可能会更新对象的不同部分。

一个例子:

我在 another answer on SO regarding this 中写了以下内容:

POST:用于修改和更新资源 POST /questions/ HTTP/1.1 主机:www.example.com/ 注意以下是错误:POST /questions/ HTTP/1.1 主机:www.example .com/ 如果尚未创建 URL,则在指定名称时不应使用 POST 创建它。这应该会导致“找不到资源”错误,因为 尚不存在。您应该首先将 资源放在服务器上。您可以使用 POST 来创建资源: POST /questions HTTP/1.1 Host: www.example.com/ 请注意,在这种情况下,未指定资源名称,新的对象 URL 路径将返回给您. PUT:用于创建资源,或覆盖它。在您指定资源的新 URL 时。对于新资源:PUT /questions/ HTTP/1.1 主机:www.example.com/ 覆盖现有资源:PUT /questions/ HTTP/1.1 主机:www.example.com/

此外,更简洁一点的是,RFC 7231 Section 4.3.4 PUT 状态(添加了重点),

4.3.4. PUT PUT 方法请求创建目标资源的状态或将其替换为请求消息有效负载中包含的表示定义的状态。

我认为 PUT 是幂等的这一事实再怎么强调也不为过:如果网络出现问题并且客户端不确定他的请求是否通过,它可以发送第二次(或第 100 次),并且由HTTP 规范,这与发送一次具有完全相同的效果。

@Jörg W Mittag:没必要。如果请求同时被修改(由其他用户或第一个请求本身通过),第二次可能会返回 409 Conflict 或其他内容。

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

@JörgWMittag 幂等标语? “发啊发啊发啊朋友啊,到底有没有区别”

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

解决方案2:

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

你可以在网上找到断言说

POST用于创建资源,PUT用于修改资源

PUT 用于创建资源,POST 用于修改资源

两者都不完全正确。

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

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

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

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

所以:

POST /expense-report

或者:

PUT  /expense-report/10929

我同意,只要涉及幂等性,它就应该胜过任何其他问题,因为错误会导致许多意想不到的错误。

如果POST可以更新资源,那怎么不是幂等的?如果我使用 PUT 更改学生的年龄并执行 10 次,那么如果我执行一次,则学生的年龄相同。

@Schneider,在这种情况下,您的服务器正在付出额外的努力来保证幂等性,但它并没有宣传它。如果他们尝试重新加载这样的 POST 请求,浏览器仍然会警告用户。

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

假设我们有可能具有两个属性的实体 - name 和 date。如果我们有一个具有现有 name 和 date 的实体,但随后仅指定 name 向它发出请求,则 PUT 的正确行为将是删除 date实体,而 POST 可能只更新指定的属性,将未指定的属性保留为发出请求之前的状态。这听起来正确/合理,还是对 PUT 的不当使用(我看到了对 PATCH 的引用,这似乎更合适,但还不存在)?

解决方案3:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

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。请参阅"REST without PUT"

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

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

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

或者从围栏的另一边:如果客户端确定了结果资源的地址,则 PUT,如果服务器确定则 POST。

我认为应该编辑这个答案,以便更清楚@DanMan 以一种非常简单的方式指出的内容。我发现这里最有价值的是最后的注释,指出 PUT 应该仅用于替换整个资源。

PATCH 至少在几年内都不是一个现实的选择,但我同意这种意识形态。

我试图理解,但使用 PUT 创建某些东西只有在客户确定资源不存在的情况下才有意义,对吧?以博客为例,假设您在几年内创建了数百篇博客文章,然后意外选择了与两年前的文章标题相同的标题。现在你已经去替换了那个帖子,这不是故意的。因此,使用 PUT 进行创建将需要客户端跟踪哪些内容被占用,哪些未被占用,并且可能导致事故和意想不到的副作用,以及拥有做两件完全不同的事情的路线?

你是对的。将博客帖子放在与现有帖子相同的 url 会导致对该现有帖子的更新(尽管您显然可以先使用 GET 进行检查)。这说明了为什么只使用标题作为 URL 是个坏主意。但是,它可以在数据中有自然键的任何地方工作……根据我的经验,这种情况很少见。或者,如果您使用 GUID

解决方案4:

huntsbot.com – 高效赚钱,自由工作

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

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

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

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

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

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

粗心可能导致人们普遍认为您只需要两个动词:GET 和 POST。 GET 获取,POST 更改。甚至 PUT 和 DELETE 也是使用 POST 执行的。 25 年后问 PUT 的真正含义可能表明我们一开始就理解错了。 REST 的流行驱使人们回到基础,我们现在必须忘记过去的错误。 POST 被过度使用,现在通常被错误地教授。最好的部分:“使用相同的数据发布两次意味着创建两个相同的 [资源]”。好点!

如果 ID 尚不存在,您如何使用 PUT 创建记录,例如在您的示例 user 5 中?你不是说update, replace if already exists吗?或者其他的东西

“更喜欢 PUT 而不是 POST”... 愿意证明这一点吗?

@thecoshman:当然。我写了这个作为一般建议。我的理由是 PUT 是幂等的,因此从网络的角度来看更好。 POST 也更通用,因此通过推荐 PUT,您可以避免将 POST 用于 PUT 就足够的情况。由于浏览器的限制,POST 也被过度使用,因此反对它的建议将对 REST 作为一个概念产生积极影响。当客户端控制 IMO 的 URL 构建时,URL 方案也有一些积极的影响,但我无法将其放入此处的评论中。

我会说使用相同数据发布两次可能会导致两个相同的用户。如果我创建我的 API,如果有人尝试使用相同的电子邮件地址发布新用户,但数据不同,我可能会发出 409。如果有人尝试使用相同的数据发布新用户,我可能会发出 303。我可能不希望我的系统能够拥有两个相同的用户。

解决方案5:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

概括:

创造:

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

PUT 在 /resources URI 或集合下以 newResourceId 作为标识符创建新资源。 PUT /resources/ HTTP/1.1 POST 在 /resources URI 或集合下创建新资源。通常标识符由服务器返回。发布/资源 HTTP/1.1

更新:

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

PUT 在 /resources URI 或集合下以 existingResourceId 作为标识符更新资源。 PUT /resources/ HTTP/1.1

解释:

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

示例:<-- 通用 – 特定 --> URI:website.example/users/john website.example - 整个站点用户 - 用户集合 john - 集合的项目,或资源 URI:website.example/users/ john/posts/23 website.example - 整个站点用户 - 用户集合 john - 集合的项目或资源帖子 - 来自 john 的帖子集合 23 - 来自 john 的帖子,标识符为 23,也是一个资源

当你使用 POST 时,你总是在引用一个集合,所以每当你说:

POST /users HTTP/1.1

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

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

POST /users/john HTTP/1.1

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

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

PUT /users/john HTTP/1.1

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

规格:

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

邮政

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

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

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

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

参考:

HTTP/1.1 规范

维基百科 - REST

统一资源标识符 (URI):通用语法和语义

这篇文章有助于我理解 POST 将“某物”作为子项添加到给定集合 (URI),而 PUT 明确定义了给定 URI 位置的“某物”。

不,PUT 不用于更新或创建。是为了更换。请注意,您可以用某些东西代替任何东西以获得创建的效果。

@7hi4g0 PUT 用于完全替换更新,换句话说,它替换。你用什么东西代替什么,或者用一个全新的东西代替什么。 PUT 不是为了进行微小的更改(除非您让客户进行微小的更改并提供整个新版本,即使是保持不变的版本)。对于部分修改,PATCH 是首选方法。

@thecoshman您可以,但是其中还涵盖了 create 并不太清楚。在这种情况下,最好是明确的。

当然,您可以发布“更新”。如果您保留以前的版本(并且您可能想要这样做的原因有很多),那么您的更新不是幂等的,因此不能用 PUT 表示。 (或者换句话说,当你足够用力地盯着它时,一切都会变成一个集合)

解决方案6:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

我想补充一下我的“务实”建议。当您知道可以检索所保存对象的“id”时,请使用 PUT。如果您需要返回一个数据库生成的 id 以供您将来查找或更新,则使用 PUT 将无法很好地工作。

所以:要保存现有用户,或者客户端生成 id 并且已验证 id 是唯一的用户:

PUT /user/12345 HTTP/1.1  <-- create the user providing the id 12345
Host: mydomain.example

GET /user/12345 HTTP/1.1  <-- return that user
Host: mydomain.example

否则,使用 POST 初始创建对象,并使用 PUT 更新对象:

POST /user HTTP/1.1   <--- create the user, server returns 12345
Host: mydomain.example

PUT /user/12345 HTTP/1.1  <--- update the user
Host: mydomain.example

实际上,它应该是POST /users。 (请注意,/users 是复数。)这具有创建新用户并使其成为 /users 集合的子资源的效果。

@DavidRR 公平地说,如何处理团体完全是另一场辩论。 GET /users 是有道理的,它可以按照您的意愿读取,但我可以使用 GET /user/ 或 POST /user(带有所述新用户的有效负载),因为它正确读取 'get me users 5' 很奇怪,但是 'get me 用户 5' 更自然。不过,我可能仍然会支持多元化:)

@thecoshman 您可以像“从用户那里得到我的 id 5”一样阅读它;)

@xuiqzy 嗯,我真的很喜欢这种思考方式,并且很好地扩展 GET /users/5/documents/4/title 就像'获取用户,从那里获取用户 5,从那里获取文档,从那里获取文档 4,从那里给我标题'

解决方案7:

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

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

PUT POST 替换现有资源或在资源不存在时创建。 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/ 标识符由服务器返回 Idempotent 即如果您两次 PUT 资源,则它没有效果。示例:尽可能多地做它,结果将是相同的。 x=1; POST 既不安全也不幂等。示例:x++;以特定方式工作 以抽象方式工作 如果您使用 PUT 创建或更新资源,然后再次进行相同的调用,则该资源仍然存在并且仍然具有与第一次调用相同的状态。发出两个相同的 POST 请求很可能会导致两个资源包含相同的信息。

比喻:

PUT 即取放原处。

POST 作为在邮局发送邮件。

https://i.stack.imgur.com/AQKrz.jpg

社交媒体/网络类比:

在社交媒体上发布:当我们发布消息时,它会创建新帖子。

为我们已经发布的消息放置(即编辑)。

@MobileMon 不,REST 方法不是 CRUD。

我会说 PUT for UPSERTS

@MobileMon no :当您创建新资源并且您不知道获取它的最终端点时发布。 PUT 用于其他情况。

解决方案8:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

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

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

POST /items 将新项目添加到已定义的资源(“项目”)。正如答案所说,它不会“创建一个组”。我不明白为什么这有 12 票。

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

这是一个公平的指导方针,但过于简单化了。正如其他答案所提到的,任何一种方法都可以用于创建和更新。

我同意这个答案,稍作修改。使用 POST 创建并使用 PUT 完全更新资源。对于部分更新,我们可以使用 PUT 或 PATCH。假设我们要更新组的状态。我们可以使用 PUT /groups/1/status 状态是请求负载或 PATCH /groups/1 使用负载中有关操作的详细信息

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

解决方案9:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

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

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

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

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

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

允许 PUT 创建资源并没有错。请注意,这意味着客户端提供了 URL。

允许 PUT 创建资源有一些非常错误的地方:客户端提供了 URL。那是服务员的工作!

@Joshcodes创建客户端ID并非总是服务器的工作。我越来越多地看到让客户端生成某种 UUID 作为资源 ID 的设计。这种设计特别适合增加规模。

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

是的,如果资源已经存在,请使用 PUT。但是,几乎在所有情况下,都应使用 POST 创建资源,并且客户端不应提供 URL。 Roy Fielding 同意此声明 FWIW:roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

解决方案10:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

使用 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),但他们还是这样做了,因为他们不知道如何解决这个问题。这种担忧体现在以下情况:

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

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

10.4.10 409 Conflict 由于与资源的当前状态冲突,请求无法完成。仅在预期用户可能能够解决冲突并重新提交请求的情况下才允许使用此代码。响应正文应该包含足够的信息让用户识别冲突的来源。理想情况下,响应实体将包含足够的信息供用户或用户代理解决问题;但是,这可能是不可能的,也不是必需的。响应 PUT 请求时最有可能发生冲突。例如,如果正在使用版本控制并且被 PUT 的实体包括对资源的更改,这些更改与早期(第三方)请求所做的更改相冲突,则服务器可能会使用 409 响应来指示它无法完成请求.在这种情况下,响应实体可能会以响应 Content-Type 定义的格式包含两个版本之间差异的列表。

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

对 ID 与系统中已有资源匹配的数据执行 POST 是“与资源的当前状态冲突”。

因为重要的部分是让客户端了解服务器拥有资源并采取适当的行动。这是“预期用户可能能够解决冲突并重新提交请求的情况”。

包含具有冲突 ID 的资源的 URL 和资源的适当先决条件的响应将为“用户或用户代理解决问题提供足够的信息”,这是 RFC 2616 的理想情况。

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

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

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

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

有关这方面的更多信息,请阅读此article。

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

@EricB。是的,在您描述的“由于与资源的当前状态冲突”的情况下,操作失败。此外,可以合理地期望用户可以解决冲突,并且消息体只需要通知用户用户名已经存在。

@Joshcodes 你能多谈谈冲突解决过程吗?在这种情况下,如果用户名已经存在,客户端是否应该提示最终用户输入不同的用户名?如果客户端实际上是在尝试使用 POST 来更改用户名怎么办? PUT 请求是否仍用于更新参数,而 POST 用于创建对象,无论是一次一个还是多个?谢谢。

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

@Zuko,在我看来,自动递增表 ID 在分布式环境中没有位置。除了存储空间之外,UUID 在各方面都非常出色。用于 ID 的 Int 是从 DB 存储成为今天更大的关注点时的遗留物。

解决方案11:

HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com

我喜欢来自 RFC 2616’s definition of PUT 的这个建议:

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

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

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

POST 适合在集合下创建新对象(并且 create 不需要是幂等的)

PUT 有利于更新现有对象(并且更新需要是幂等的)

POST 也可用于对现有对象的非幂等更新(尤其是更改对象的一部分而不指定整个事物——如果您考虑一下,创建集合的新成员实际上是这种类型的特例更新,从集合的角度来看)

当且仅当您允许客户端命名资源时,PUT 也可用于创建。但是,由于 REST 客户端不应该对 URL 结构做出假设,因此这不符合预期的精神。

“POST 也可用于对现有对象的非幂等更新(尤其是在不指定整个对象的情况下更改对象的一部分”这就是 PATCH 的用途

原文链接:https://www.huntsbot.com/qa/7QgL/what-is-the-difference-between-post-and-put-in-http?lang=zh_CN

huntsbot.com – 高效赚钱,自由工作

猜你喜欢

转载自blog.csdn.net/kalman2019/article/details/128231559