接口幂等性
在我们实际开发场景当中,很多时候都会有重复消费的业务场景出现.这是我们不希望出现的.例如我们在支付订单时,往往会遭受卡顿的情况,我们如果反复点击支付
,如何保持我们只消费一次的现象,成为了一个难题.
这时我们希望此时是数据更新是幂等的.
那什么是幂等性呢?
幂等是数学里面的一个概念.我们可以用函数表达式来表达
而运用到我们程序的开发过程当中,则是指在同一个业务场景下,执行一次或者多次对业务状态的影响都是一致的
.
那什么时候会引起这种幂等性的问题呢?
例如
- 网络波动, 可能会引起重复请求。
- 用户重复操作,用户在操作时候可能会无意触发多次下单交易,甚至没有响应而有意触发多次交易应用。
- 使用了失效或超时重试机制(Nginx重试、RPC重试或业务层重试等)。(
也就是执行业务时突然阻塞,一段时间超时以后重试又发送一个请求或者一个消息重发导致重复消费
). - 使用浏览器后退按钮重复之前的页面操作,导致重复提交表单。
这导致我们需要幂等性的需求出现.
而有些业务天生就是幂等.
例如查询
时,我们查询一万次与查询一次的结果时是一样的.
还有就是删除一条数据时,我们删除过后,无论你再发多少请求过来,数据已经被删除了
,不存在重复删除这个问题.
而对于增加和更新这两个业务场景我们就不得不采取一些措施来保证接口的幂等性.
接下来模拟一下这些业务场景的出现.
我们先来模拟一下增加数据出现幂等性问题的原因.
我们首先创建一个user表,表结构如下
接下来构建三层架构.(技术栈为Spring Boot,Thymeleaf,Mybatis-Plus)
我们撰写一个简单的页面
新增页面
我们在添加用户的让线程睡上3秒,模拟网络卡顿的情况.
我们接下来疯狂点击增加,浏览器出现以下状态
然后页面跳转我们发现增加了许多记录
这就导致啦幂等性问题的出现.
那我们可以怎么处理呢?想想,我们想要它能够幂等就得保证唯一,我们能通过什么手段保证传过来这么多次是唯一的呢?
我们是不是可以模拟一个一字段,或者说一个标志,当你进入这个页面之后就会携带这样一个标志,无论你点击多少次都会带上这个标志,只不过第一次来的时候,我们就会把这个标志剔除
,那么接下来的请求我们判定你这样的标志在不在我这里存在.由于第一次来将标志已经剔除,后面的请求自然就是不存在
,所以我们就不会让他添加,构成幂等性的条件.
那我们得借用一下redis老哥啦,我们在进入这个页面随机生成一个UUID携带,然后配置一个拦截器,当我们请求添加时,拦截器拦下,检查是否携带这样一个标志,如果存在,我们剔除,如果不存在,我们直接打回.
改写原来的跳转接口逻辑
改写原来页面提交的参数
添加注解,用来声明需要拦截的方法
配置拦截器
@Component
<