为什么一直想着幂等性?
在一次后台设计外审中关于某个接口的设计是否是幂等性开始,从那之后就对这个幂等性有点兴趣,然后在一次关注的测试的公众号推送的一篇文章中看到了“幂等性”
何为幂等性
初次理解是,对于同样的请求,后台处理过一次之后进入到某一个状态后再来一次同样的请求,后台接口看似不进行处理,但实际是处理了,只是没有去改变后台或者服务器的状态,不会返错误,也就是就是一个操作或者接口,不管你调多少次,每次执行的结果都跟第一次一样。
看看官方定义
一个HTTP方法是幂等的,指的是同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。在正确实现的条件下,GET,HEAD,PUT和DELETE 等方法都是幂等的,而 POST 方法不是。所有的 safe 方法也都是幂等的。
幂等性只与后端服务器的实际状态有关,而每一次请求接收到的状态码不一定相同。例如,第一次调用DELETE 方法有可能返回 200,但是后续的请求可能会返回404。DELETE 的言外之意是,开发者不应该使用DELETE方法实现具有删除最后条目功能的 RESTful API。
服务器不一定会确保请求方法的幂等性,有些应用可能会错误地打破幂等性约束。
幂等的使用
在对数据准确性要求很高的领域,比如金融、银行、电商行业就很需要对数据处理接口做到幂等性。
比如,在支付的时候突然碰到网络异常等其他原因导致后台接口已经实施扣款,但是前端返回提示支付失败,当用户再进行重试的时候又成功扣了一次款,那问题就大了。在这种场景下这个扣费的接口就需要实现幂等性,第一次扣除成功后服务器状态已经发生变化,再进行同样的扣款请求时就不要再进行再一次的扣款,服务器的状态与上一次一样。
所以对于一些重要的接口或者操作,要求后台保证其幂等性的。因为客户端可能有重试机制,另外中间人攻击可能会进行请求的重放,这些都有可能导致接口被多次调用。
实现幂等
参考:公众号“测试圈TC”-“测试同学必会系列之如何进行幂等性的测试”
- MVCC: 多版本并发控制,乐观锁的一种实现,在数据更新时需要去比较持有数据的版本号,版本号不一致的操作无法成功;
- 去重表:利用数据库表单的特性来实现幂等,常用的一个思路是在表上构建唯一性索引,保证某一类数据一旦执行完毕,后续同样的请求再也无法成功写入。比如博客上面要想防止一个人重复点赞,可以设计一张表,将博客id与用户id绑定建立唯一索引,每当用户点赞时就往表中写入一条数据,这样重复点赞的数据就无法写入。
- TOKEN机制: 这种机制就比较重要了,适用范围较广,有多种不同的实现方式。其核心思想是为每一次操作生成一个唯一性的凭证,也就是token。一个token在操作的每一个阶段只有一次执行权,一旦执行成功则保存执行结果。对重复的请求,返回同一个结果。以电商平台为例子,电商平台上的订单id就是最适合的token。当用户下单时,会经历多个环节,比如生成订单,减库存,减优惠券等等。每一个环节执行时都先检测一下该订单id是否已经执行过这一步骤,对未执行的请求,执行操作并缓存结果,而对已经执行过的id,则直接返回之前的执行结果,不做任何操作。这样可以在最大程度上避免操作的重复执行问题,缓存起来的执行结果也能用于事务的控制等。
如何测试幂等性
- 设计前期:需要识别需要实现幂等的接口,并与开发确认
- 测试:反复调用
- 测试:反复调用的时候修改看似无关紧要的参数,是否会破坏幂等性