表单重复提交-接口幂等性问题

接口幂等性,就是一次请求和多次请求某一个资源对于资源本身应该具有同样的结果

为什么需要实现幂等性

在接口调用时,一般情况下都能
正常返回消息不会重复提交,不过在某些情况下可能会出现问题

1、前端重复提交表单:

在填写表格时,用户填写完成提交,很多时候会因网络波动没有及时对用户做出提交成功的响应,导致用户认为没有成功提交,然后一直点提交按钮,这时就会发生重复提交表单请求;

2、用户恶意进行刷单:

比如在用户投票时,如果用户重复提交投票,这样会使投票结果与实际不符;

3、接口超时重复提交:

在网络波动等原因造成接口超时时,客户端或者用户会重试,导致一个请求提交多次;

4、消息进行重复消费:

当使用MQ中间件时,如果发生消息中间件出现错误未及时提交消费信息,会导致重复消费;

使用幂等性最大的优势在于使接口保证任何幂等性操作,避免因重试等操作造成系统产生未知的问题;

幂等性的解决方案

1、唯一索引

使用唯一索引可以避免同样数据的反复插入,当插入重复数据时数据库会抛出异常,保证了数据的唯一性;
适用于插入操作;

2、数据库乐观锁

用乐观锁的原理去实现:为表增加一个version字段,充当当前数据的版本标识;或者基于状态控制(状态机)
更新时,查询条件里加上上次待更新数据的版本标识,更新操作里也将该版本号加一;
update tableName set count = count +1,version = version +1 where version = #{version};

如果更新失败,这说明已经有其他的请求去更新数据了,本次提示更新失败,让用户重试即可;

适用于更新操作;

3、使用悲观锁

查询数据时用for update将行数据锁住,在同一时刻只允许一个请求获得锁,其他请求等待; select * from account where id =123 for update;

4、分布式锁

幂等的本质是分布式锁的问题,分布式锁正常可以通过redis或 zookeeper来实现;
在分布式环境下,锁定全局唯一资源,使多个请求串行化,实际表现为互斥锁,可以防止重复,以此来解决幂等性问题;

5、token+redis机制(通用性强)

token机制的核心思想,是为每一次操作都生成一个唯一性的凭证,也就是token;

5.1服务端提供获取Token的接口,该Token可以是一个序列号,也可以是一个分布式ID或者UUID串;

5.2客户端调用接口获取Token,这时候服务端会生成一个Token串。
5.3然后将该串存入Redis数据库中,以该Token作为Redis的键(注意设置过期时间)。
5.4将Token返回到客户端,客户端拿到后应存到表单隐藏域中。
5.5 客户端在执行提交表单时,把Token存入到Headers中,执行业务请求带上该Headers。
5.6 服务端接收到请求后从Headers中拿到Token,然后根据Token到Redis中查找该key是否存在。
5.7服务端根据Redis中是否存该 key进行判断,如果存在就将该 key删除,然后正常执行业务逻辑。如果不存在就抛异常,返回重复提交的错误信息。
注意,在并发情况下,执行 Redis查找数据与删除需要保证原子性,否则很可能在并发下无法保证幂等性。其实现方法可以
1.使用分布式锁 setnx;
2.使用Lua表达式;对redis中是否存在token以及删除的代码逻辑建议用Lua脚本实现,以此来保证多个操作的原子性;
适用于插入操作,更新操作,删除操作;

6、基于redis命令setnx实现

6.1客户端先请求服务端,会拿到一个能代表这次请求业务的唯一字段。
6.2 将该字段以 setnx的方式存入 redis中,并根据业务设置相应的超时时间timeout。
6.3如果设置成功,则证明这是第一次请求,则执行后续的业务逻辑。
6.4如果设置失败,则证明这不是第一次请求,已经执行过当前请求,直接返回即可。
setnx key value:当且仅当key不存在时,将key的值设为value,
并返回1。若给定的key已经存在,则setnx不做任何动作,并返回0。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值