一、什么情况下需要幂等
用户多次点击按钮
用户页面回退再次提交
微服务相互调用,由于网络问题,导致请求失败,feign触发重试机制
二、幂等性解决方案
2.1 token机制(令牌)
在加载页面详情时候,服务器会顺便生成一个token一起返回给前端,服务端同时也在Redis中保存这个token数据,前端并不展示这个token,但当页面点击提交按钮时候,会在携带上这个token参数,此时后端便会先校验前端提交请求的token与redis中的token是否一致,一致的话即是第一次请求,执行业务代码并在Redis中删除该token,当用户还是携带上次的验证码多次提交,此时服务器判断redis中验证码不存在,便可能是多次提交的情况,不再执行业务代码,保证业务的幂等性,不被重复执行。
问题1:先删除token还是后删除token
·先删除可能导致, 删除token以后,服务器闪断,业务确实没有执行,此时重试还带上之前token,由于防重设计导致,请求还是没有走到执行业务代码那块逻辑。
·后删除可能导致,业务处理成功,但是服务闪断,出现超时,没有删除token,别人继续重试,导致业务被执行两遍
解决:我们最好设计为先删除token,如果业务调用失败,就重新获取token再次请求。
问题2:如何保证token 获取、比较和删除必须是原子性
redis.get(token) 、token.equals、 redis.del(token)如果这3个操作不是原子,可能导致,高并发下,都get到同样的数据,判断都成功,导致业务并发执行
解决:可以在redis使用lua脚本完成这个操作
// redis+lua脚本 原子验证令牌防止重复提交攻击
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
String orderToken = "现在的令牌"