您需要知道,在编写基于HTTP的API时,必须使所有GET请求都是幂等的。 幂等是一个奇特的词,通常表示“只读”。 如果您多次重复幂等函数,则应始终获得相同的结果。
编写HTTP API时,绝对必须确保GET请求除了对现有数据进行读取和响应外不执行任何操作。 这样做的原因不是迷信。 也没有帮助我们整齐地组织HTTP谓词的方法-我们的行业在(SOAP)之前完全忽略了网络API中的HTTP谓词,而它们也会再次出现(GraphQL,gRPC),因为HTTP是制作API(REST)的不好方法。)HTTP及其所有陷阱都用于Web浏览器的导航,静态文件访问和资源加载; 该协议针对现代API需求进行了精心设计。
但是,关于Web浏览器的那条注释恰恰是为什么您不应该在任何导致状态发生变化的请求上使用GET动词的原因。 浏览器会无意中触发对最终用户单击的任何超链接的GET请求,并默默地针对静态资源(例如<img>标签)触发GET。 从历史上看,这对于Web来说是一个非常非常糟糕的安全性问题,因为它实质上允许任何网站劫持用户的浏览器来发送不需要的请求。 从安全的角度来看,Web曾经是一个悲剧,因为整个浏览器/ HTML / HTTP系统本质上都是基于代码和数据的混合。 浏览器是远程代码执行机。 (为了进行比较,请考虑移动应用程序没有像XSS / CSRF这样的问题,这些问题曾经是(现在仍然是)网络流行。)
与其他HTTP动词相比,攻击者更容易诱骗用户的浏览器触发GET请求。 因此,您应该非常小心GET端点的功能。 您可能应该将它们保留为只读。
但是,仅仅因为您的端点是只读的,并不意味着它们是幂等的。 如果您的服务器管理状态(他们几乎都管理状态),那么就没有幂等API。 简而言之,幂等是错误的词。
在客户机/服务器情况下,幂等是服务器上的实现细节。 从客户端的角度来看,对于服务器控制的状态,不可能有幂等的东西。
我已经进行过多次辩论,因为一些程序员将其视为GET请求是/应该是幂等的基本定律。 我认为这样的事情不仅是错误的,而且实际上是不可理解的废话,对我来说肯定是很刺耳的。 我曾经有一个程序员这样对我说:
我将GET方法编写为幂等的。 这很棒,因为无论我在该资源上调用GET多少次,我都知道我没有做任何更改,而且我将始终获得相同的响应。
实际上,GET请求的客户端无法保证他们将获得相同的响应。 那就是问题所在。
考虑以下假设的呼叫顺序,这些顺序可能完全发生在现实的杂货清单应用中:
// GET /grocies/list is a 100% read-only implementation
Request: ---> HTTP GET /groceries/list Response: <--- [ 'eggs', 'milk' ]
Request: ---> HTTP GET /groceries/list Response: <--- [ 'eggs', 'milk', 'butter' ]
Request: ---> HTTP GET /groceries/list Response: <--- [ 'eggs', 'milk', 'butter', 'bread' ]
“什么?!” 你抗议。 “如果GET的制作正确,为什么每次调用它时都会将新商品添加到购物清单? 那不是幂等的!” 究竟。 但是即使API设计成具有幂等的GET请求,这种精确的交互也可以并且确实会在API中发生。 基本上,每一个客户服务器API每天都在不断发生这种情况。 这就是为什么。
同样,幂等性是服务器的私有实现细节。 这是服务器的业务,其他任何人都不需要了解或关心。 从客户的角度来看,这个概念完全是胡说八道。 这是上述交换的完整图片:
(You) Request: ---> HTTP GET /groceries/list Response: <--- [ 'eggs', 'milk' ]
(Your spouse) Request: ---> HTTP POST /groceries/list/ ?append=butter Response: <--- [ 'eggs', 'milk', 'butter' ]
(You) Request: ---> HTTP GET /groceries/list Response: <--- [ 'eggs', 'milk', 'butter' ]
(Your spouse) Request: ---> HTTP POST /groceries/list/ ?append=bread Response: <--- [ 'eggs', 'milk', 'butter', 'bread' ]
(You) Request: ---> HTTP GET /groceries/list Response: <--- [ 'eggs', 'milk', 'butter', 'bread' ]
您不知道,另一个客户端已将POST请求发送到同一资源。 从您的角度来看,您所看到的只是在GET请求之间服务器的状态正在急剧变化。
只要服务器控制可变状态,客户端就永远不会对他们的GET请求是否正在改变该状态有任何概念。
客户端将始终必须对后续的GET请求处理不同的结果。 它无法知道是什么原因导致更改,以及是否是GET请求本身影响了更改。 没有办法知道,也没有理由要照顾。 并不是GET方法是幂等的或不是幂等的。 正是幂等的概念不适用于客户的观点。
幂等可以作为客户端服务器中的一个概念存在,但仅在没有服务器管理状态时才存在。 您必须使用功能性编程专着中的示例,返回到幂等函数的更经典示例。 基本情况是一个仅在其输入上操作并且既不使用也不操纵任何共享状态的函数:
// idempotent because it relies only on its input '5' Request: ---> HTTP GET /math/square/5 Response: <--- 25
From: https://hackernoon.com/http-get-requests-arent-idempotent-because-there-s-no-such-thing-ca57d90f6cf0