接口防刷设计实现
redis+apo 实现限流防刷
设计注解类 注解类自带参数 maxcount 最大次数, time 时间, limitType限流类型,limitMag 提示信息
实现思路
设置切面类 aspect 自定义注解limit 并实现注解
注解实现类思路
redis实现对每个ip的记录 使用redis increment实现自增 比较当前ip的单位时间内的访问次数 与最大次数的比较
如果没有 可以新增key key的设置可以是 ip+方法名 或者其他 实现自定义接口单独限制
并为 key设置过期时间 实现单位时间内实现限制
代码参考
@Aspect
@Component
@RequiredArgsConstructor
public class RateLimiterAspect {
@Resource(name = "defaultRedisUtil")
RedisUtil redisUtil;
@Before("@annotation(rateLimiter)")
public void doBefore(JoinPoint point, LxRateLimit rateLimiter) throws Throwable {
int time = rateLimiter.time();
int count = rateLimiter.count();
long total = 1L;
String key = getCombineKey(rateLimiter, point);
try {
if (redisUtil.hasKey(key)) {
total = redisUtil.incr(key, 1); // 请求进来,对应的key加1
if (total > count) {
throw new IpExceedException(rateLimiter.limitMsg());
}
} else {
redisUtil.set(key, 1, time); // 初始化key
}
} catch (IpExceedException e) {//频繁进入
throw e;
} catch (Exception e) {
throw new Exception("网络繁忙,请稍候再试");
}
}
// 获取限流key
public String getCombineKey(LxRateLimit rateLimiter, JoinPoint point) {
StringBuffer stringBuffer = new StringBuffer("key");
if (rateLimiter.limitType() == 0) {//IP
stringBuffer.append(WebUtil.getIP(WebUtil.getRequest())).append("-");
}
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class<?> targetClass = method.getDeclaringClass();
stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
return stringBuffer.toString();
}
}
/**
* 限流注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LxRateLimit {
// 限流时间,单位秒
int time() default 60;
// 限制最大请求次数
int count() default 100;
// 限流类型(默认为IP限流) 0:IP
int limitType() default 0;
// 限流后返回的提示信息
String limitMsg() default "Frequent visits, please try again later";
}
补充:
文章评论