概念
接口幂等性是指用户对于同一操作发起的一次请求和多次请求的结果是一致的,不会因为多次点击而产生副作用。
场景:假如用户进行下单操作的时候多次点击如果不能保证接口的幂等性就会提交多次订单请求,或者微服务之间当订单服务调用库存服务的时候如果出现了调用异常,那么我们并不知道是库存已经减了之后发生的异常还是由于网络原因库存还没减发生的异常。
哪些情况需要防止
- 用户多次点击
- 用户页面退回再提交
- 微服务互相调用,由于网络问题导致请求失败,Feign触发重试机制
接口幂等性的解决方法
接口幂等性是指用户因为网络或者恶意多次请求接口导致数据的重复提交产生的问题,所以接口要保证幂等性,比如在用户在下订单的时候即使重复点击结算按钮也只能给服务器提交一次结算请求。
解决方法:当用户访问该提交页面的时候就生成一个令牌给用户并且将这个令牌保存在redis或者mysql中,之后用户在这个页面提交的数据必须携带这个令牌,后端接收到用户的请求拿着令牌与redis中的令牌做对比,如果存在那么就开始执行相应的逻辑并且删除该令牌,之后再执行响应的逻辑,否则就快速响应结束请求。那么需要注意的是,令牌的对比和删除要保证原子性,所以我们采用redis的lua脚本的方式来解决这个问题。
String orderToken = orderSubmitVo.getOrderToken(); String key = OrderConstant.USER_ORDER_TOKEN_PREFIX + userId; //验证令牌 String script = "if redis.call('get', KEYS[1]) == ARGV[1] " + "then return redis.call('del', KEYS[1]) else return 0 end"; Long result = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(key), orderToken); if (result == 0L){ //令牌验证失败 response.setCode(1); return response; }else { //令牌验证成功 }