订单重复提交问题
1.原因:
1.网络延迟的情况下让用户有时间点击多次提交按钮导致表单重复提交.
2.表单提交后用户点击浏览器的刷新导致表单重复提交
3.用户提交表单后,点击浏览器[后退]按钮回退到表单页面后进行提交
2.三种方法
1.用JavaScripct的方式在客户端处理.
设置一个表示只让他提交一次,用于针对第一种原因,多次点击按钮提交.
var isCommitted = false;//表单是否已经提交标识,默认为false
function dosubmit(){
if(isCommitted==false){
isCommitted = true;//提交表单后,将表单是否已经提交标识设置为true
return true;//返回true让表单正常提交
}else{
return false;//返回false那么表单将不提交
}
}
2.利用session防止表单重复提交
步骤:
1.客户端申请token
2.服务器端生成token,并存放在session中,同时将token发送到客户端
3.客户端存储token,在请求提交时,同时发送token信息
4.服务器端统一拦截同一个用户的所有请求,验证当前请求是否需要被验证(不是所有请求都验证重复提交)
5.验证session中token是否和用户请求中的token一致,如果一致则放行
6.session清除会话中的token,为下一次的token生成作准备
7.并发重复请求到来,验证token和请求token不一致,请求被拒绝
决绝策略:
-
存储session域中的Token(令牌)与表单提交的Token(令牌不同).
-
当前用户的Session中不存在Token(令牌)
-
用户提交的表单数据没有Token(令牌)
3.使用Redis incrde 原子性递增
我们可以使用Redis incrde 原子性递增,来解决这种高并发的秒杀或者分布式序列号生成等场景。鉴于本场景我们
只用他来做计数实现间隔时间内只接收一次请求。
实现逻辑:
在提交订单之后使用Redis的incr设置一个递增的KEY(根据自己的需要设定但是要保证每一个人的唯
一),来判断该KEY的数值,如果等于1说明这是第一次请求,发送短信记录日志,并设置有效期,如果不等于的
话说明是间隔时间内多次请求,就提示请求频繁,稍后重试。
String orderNum=memberId+productId;
long count = redisTemplate.opsForValue().increment(orderNum, 1);
if (count == 1) {
//设置有效期2秒
redisTemplate.expire(orderNum, 2, TimeUnit.SECONDS);
}
if (count > 1) {
resultMap.put("retCode", "500");
resultMap.put("retMsg", "请不要重复提交订单");
return resultMap;
}