为什么HTTP方法PUT应该是幂等的而不是实现RestFul服务中的POST?

时间:2018-02-22 10:50:25

标签: java rest jax-rs

互联网上有许多可用资源,其中讨论了PUT与POST。但是我无法理解它会如何影响下面为RestFul服务完成的Java实现或后端实现?我查看的链接如下:

https://www.keycdn.com/support/put-vs-post/

https://spring.io/understanding/REST#post

https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

http://javarevisited.blogspot.com/2016/10/difference-between-put-and-post-in-restful-web-service.html

例如,假设有一个RestFul Web服务用于Address。 因此POST /addresses将完成更新地址的工作,PUT /addresses/1将完成创建地址的工作。 现在HTTP方法PUT和POST如何控制我们的服务代码在幕后做什么?

PUT /addresses/1 

最终可能会在数据库中创建同一地址的多个条目。

所以我的问题是,为什么幂等行为与HTTP方法有关?

如何通过使用特定的HTTP方法来控制幂等行为?或者只是建议的指南或标准做法?

我不是在寻找什么是幂等行为的解释,但是是什么让我们标记这些HTTP方法呢?

6 个答案:

答案 0 :(得分:3)

这是特定于HTTP的。由您链接的RFC声明https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html(请参阅本答复底部的最新RFC链接)。它没有被描述为REST的一部分:https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

现在你写了,

  

我不是在寻找对幂等行为的解释   是什么让我们标记这些HTTP方法呢?

幂等操作总是有相同的结果(我知道你知道),但结果与HTTP响应不同。从HTTP角度来看,显而易见的是,使用任何方法的多个请求甚至所有相同的参数都可以具有不同的响应(即,时间戳)。所以他们实际上可能有所不同。

不应该改变的是操作的结果。因此,多次调用PUT /addresses/1 不应创建多个地址。

正如你所看到的,它被称为PUT而不是CREATE是有原因的。如果资源不存在,它可能会创建资源。如果它存在,那么它可能会用新版本(更新)覆盖它,如果它完全相同应该在服务器上什么也不做,并产生相同的答案,好像它是相同的请求(因为它可能是相同的请求重复,因为上一个请求被中断,客户端没有收到响应。)

与SQL PUT相比,INSERT OR UPDATE更像是INSERTUPDATE

  

所以我的问题是,为什么幂等行为与HTTP方法有关?

它类似于HTTP方法,因此一些服务(代理)知道,如果请求失败,他们可以安全地尝试(不是在安全的HTTP方法方面,而是在幂等性方面)重复它们。

  

如何通过使用特定的HTTP方法来控制幂等行为?

我不确定你要求的是什么。 但是:

  • GET,HEAD只返回数据,它不会改变任何东西(除了一些日志,统计数据,元数据?)所以它是安全的和幂等的。
  • POST,PATCH可以做任何不安全或无意义的事情
  • PUT,DELETE - 不安全(他们更改数据)但是它们是幂等的,所以重复它们是“安全的”。

这基本上意味着安全方法可以通过代理,缓存,网络爬虫等安全地进行,而无需改变任何内容。幂等可以通过软件重复,它不会改变结果。

  

或者只是建议的指南或标准做法?

这是“标准”。也许RFC还不是标准的,但它最终会成为一个,我们没有其他任何我们可以(也应该)遵循的东西。

修改

由于上面提到的RFC已经过时,所以有关该主题的当前RFC的一些参考文献:

感谢Roman Vottner提出建议。

答案 1 :(得分:2)

  

所以我的问题是,为什么幂等行为与HTTP方法有关?   我不是在寻找什么是幂等行为的解释,而是什么让我们标记这些HTTP方法呢?

因此,在消息交换中,通用的,域不可知的参与者可以做出有用的贡献。

RFC 7231在其idempotent

的定义中引用了一个具体示例
  

区分幂等方法,因为如果在客户端能够读取服务器响应之前发生通信故障,则可以自动重复请求。例如,如果客户端发送PUT请求并且在收到任何响应之前关闭了底层连接,则客户端可以建立新连接并重试幂等请求。它知道重复请求将具有相同的预期效果,即使原始请求成功,尽管响应可能不同。

客户或中间人不需要了解您的定制API或其底层实施,以此方式行事。所有必要的信息都在规范中(RFC 7231&PUTidempotent的定义),以及服务器宣布该资源支持PUT。

请注意,PUT需要幂等请求处理,但不禁止POST。拥有幂等POST请求处理程序,甚至是safe的处理程序是没错的。但是通用组件只有元数据和HTTP规范可供使用,它们不会知道或发现POST请求处理程序是幂等的。

  

我无法理解它会如何影响下面为RestFul服务完成的Java实现或后端实现?

没有魔力;使用PUT不会自动更改服务的底层实现;从技术上讲,它甚至不会限制底层实施。它所做的事情清楚地记录了责任所在。

类似于Fielding's 2002 observation,关于GET是安全的

  

HTTP不会尝试要求GET的结果是安全的。什么   它确实要求操作的语义是安全的,并且   因此它是实现的错误,而不是接口   或该接口的用户,如果发生任何结果   导致财产损失(金钱,BTW,被视为财产   这个定义的缘故)。

要意识到的一件重要事情是,就HTTP而言,没有资源层次结构"。 /addresses/addresses/1之间没有任何关系 - 例如,一个消息对另一个的缓存表示没有影响。 /addresses是"集合"的概念并且/addresses/1是/ addresses集合中的"项目#34;是一个实现细节,对原始服务器是私有的。

(过去的情况是POST的语义会引用从属资源,例如参见RFC 1945;但即使这样,下属的标识符的拼写也不受约束。)

  

我的意思是PUT /员工是可以接受的,或者必须是PUT /员工/< employee-id>

PUT /employee具有&#34的语义;用我提供的表示替换/ employee的当前表示"。如果/employee是集合的表示,那么通过PUT传递集合的新表示来修改该集合是完全没错的。

GET /collection

200 OK

{/collection/1, collection/2}

PUT /collection

{/collection/1, /collection/2, /collection/3}

200 OK

GET /collection

200 OK

{/collection/1, /collection/2, /collection/3}

PUT /collection

{/collection/4}

200 OK

GET /collection

200 OK

{/collection/4}

如果这不是你想要的;如果你想追加到集合,而不是替换整个表示,那么PUT在应用于集合时具有错误的语义。您需要将项目表示设置为项目资源,或者您需要在集合上使用其他一些方法(POST或PATCH是合适的)

GET /collection

200 OK

{/collection/1, collection/2}

PUT /collection/3

200 OK

GET /collection

200 OK

{/collection/1, /collection/2, /collection/3}

PATCH /collection

{ op: add, path: /4, ... }

200 OK

GET /collection

200 OK

{/collection/1, /collection/2, /collection/3, /collection/4 }

答案 2 :(得分:1)

  

如何使用特定的HTTP控制幂等行为   方法?或者它只是一个指南或标准实践   建议?

更多关于HTTP specification,应用必须遵循这些规范。没有什么能阻止你改变服务器端的行为。 Web服务和Restful Web服务之间总是存在差异。

考虑一些使用servlet的遗留应用程序。 Servlet曾经有doGetdoPost方法。出于安全原因并在doPost上将数据存储在server / db上,始终建议doGet。因为信息嵌入在请求中,并且不会暴露给外部世界。

即使没有什么可以阻止您在doGet中保存数据或在doPost中返回一些静态页面,因此它只是关注以下基本规范

答案 3 :(得分:1)

  

所以我的问题是,为什么幂等行为与HTTP方法有关?

因为HTTP规范如此说明:

  

4.2.2。幂等方法

     

请求方法被视为"幂等"如果预期的影响      使用该方法的多个相同请求的服务器是      与单个此类请求的效果相同。请求方法      由本规范,PUT,DELETE和安全请求方法定义      是幂等的。

(资料来源:RFC 7231

为什么规格说这个?

  • 因为它可用于实现基于HTTP的系统,以便能够区分幂等和非幂等请求。 "方法" type提供了一种区分的好方法。

  • 因为HTTP规范的其他部分谓词能够区分幂等方法;例如代理和缓存规则。

  

如何使用特定的HTTP方法控制幂等行为?

由服务器实现PUT&删除以具有幂等行为。如果服务器没有,则违反 HTTP规范。

  

或者只是建议的指南或标准做法?

必需行为。

现在你可以忽略这个要求(没有协议警察!)但如果你这样做,它可能会导致你的系统崩溃。特别是如果你需要将它们与其他人实现的系统集成......谁可能编写他们的客户端代码,假设它重放PUT或DELETE,你的服务器不会说"错误"。 / p>

简而言之,我们使用HTTP之类的规范,以便我们的系统可以互操作。但是,如果每个人的代码都能正确实现规范,那么这种策略才能正常运行。

答案 4 :(得分:0)

通常在Rest API中。我们用过

POST - 添加数据 GET - 获取数据 PUT - 更新数据 删除 - 删除数据

阅读以下帖子以获得更多想法。

REST API Best Practices

答案 5 :(得分:0)

POST - 通常不是幂等的,因此多次调用将创建具有不同ID的多个对象

PUT - 根据您要应用的URI中的ID"创建或更新"查询数据库因此,一旦创建资源,每次下一次调用都不会对后端状态产生影响

即。后端在生成新的/更新的现有存储对象方面存在明显差异。例如。假设您使用的是MySQL并自动生成ID:

POST最终会以INSERT查询

结束

PUT将以INSERT ... ON DUPLICATE KEY UPDATE查询

结束