通常我们可以在前端通过防抖和节流来解决短时间内请求重复提交的问题,如果因网络问题、Nginx重试机制、微服务Feign重试机制或者用户故意绕过前端防抖和节流设置,直接频繁发起请求,都会导致系统防重请求失败,甚至导致后台产生多条重复记录,此时我们需要考虑在后台增加防重设置。
考虑到微服务分布式的场景,这里通过使用Redisson分布式锁+自定义注解+AOP的方式来实现后台防止重复请求的功能,基本实现思路:通过在需要防重的接口添加自定义防重注解,设置防重参数,通过AOP拦截请求参数,根据注解配置,生成分布式锁的Key,并设置有效时间。每次请求访问时,都会尝试获取锁,如果获取到,则执行,如果获取不到,那么说明请求在设置的重复请求间隔内,返回请勿频繁请求提示信息。
1、自定义防止重复请求注解,根据业务场景设置了以下参数:
- interval: 防止重复提交的时间间隔。
- timeUnit: 防止重复提交的时间间隔的单位。
- currentSession: 是否将sessionId作为防重参数(微服务及跨域前后端分离时,无法使用,Chrome等浏览器跨域时禁止携带cookie,每次sessionId都是新的)。
- currentUser: 是否将用户id作为防重参数。
- keys: 可以作为防重参数的字段(通过Spring Expression表达式,可以做到多参数时,具体取哪个参数的值)。
- ignoreKeys: 需要忽略的防重参数字段,例如有些参数中的时间戳,此和keys互斥,当keys配置了之后,ignoreKeys失效。
- conditions:当参数中的某个字段达到条件时,执行防重配置,默认不需要配置。
- argsIndex: 当没有配置keys参数时,防重拦截后会对所有参数取值作为分布式锁的key,这里时,当多参数时,配置取哪一个参数作为key,可以多个。此和keys互斥,当keys配置了之后,argsIndex配置失效。
```
package com.gitegg.platform.base.annotation.resubmit;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;