后端接口限流
如果有人使用token+postman多次调用服务端某个接口,那么会造成服务繁忙,因此我们需要设置来自同一用户的请求时间间隔
使用AOP+redis进行请求冷却设置
设计思路:
使用AOP+自定义注解对需要限流的服务进行切面配置
在切面中获得当前请求的用户id
将用户id作为key存入redis缓存中,value可以不设置,通过读取注解上的请求限流时间来设置key的失效时间
下一次请求被AOP拦截到则进行一次获取key的操作,如果key失效不存在则服务器受理请求,否则直接返回拒绝服务
初步方案
配置切面
@Component
@Aspect
public class ApiAspect {
@Autowired
private RedisCache redisCache;
@Pointcut("@annotation(com.os467.annotation.ApiLimit)")
public void pt(){
}
@Around("pt()")
public Object limitRequest(ProceedingJoinPoint joinPoint) throws Throwable {
Long userId = SecurityUtils.getUserId();
if (redisCache.getCacheObject("apiLimit:" + userId) == null) {
//记录正在发生请求
redisCache.setCacheObject("apiLimit:" + userId, "");
//获取当前增强方法的标签信息
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
//获取超时时间
int timeout = method.getAnnotation(ApiLimit.class).timeout();
redisCache.expire("apiLimit:" + userId,timeout, TimeUnit.SECONDS);
} else {
//上一个请求还未结束,拒绝服务
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR, "请勿重复操作");
}
//增强方法的返回值
Object ret = null;
try {
ret = joinPoint.proceed();
} catch (Throwable throwable) {
throw throwable;
}
return ret;
}
}
此方案可以初步排除更新操作的重复操作,但是在添加操作中失效了
分析原因可能是因为多个线程同时判断冷却标记为null从而导致AOP拦截失效
增强方案
解决方案
使用双重if判断+线程同步代码块的方案 来保证只有一个请求被受理
//第一次检查缓存中是否有冷却标记
if (redisCache.getCacheObject("apiLimit:"+userId) != null){
//上一个请求还未结束,拒绝服务
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR, "请勿重复操作");
}else {
//静态代码块,持有当前切面类的对象锁
synchronized (this) {
if (redisCache.getCacheObject("apiLimit:" + userId) == null) {
//记录冷却标记
redisCache.setCacheObject("apiLimit:" + userId, "");
//获取当前增强方法的标签信息
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
//获取超时时间
int timeout = method.getAnnotation(ApiLimit.class).timeout();
//设置冷却标记失效时间
redisCache.expire("apiLimit:" + userId,timeout, TimeUnit.SECONDS);
} else {
//上一个请求还未结束,拒绝服务
return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR, "请勿重复操作");
}
}
}
此时对用户A的多次重复请求已经做了冷却限制,保证服务器在5秒内只受理一次用户A的请求
此时有一个问题
当前线程同步代码块使用的是AOP监视器的对象锁,因此思考是否会对其它线程请求造成阻塞影响?
- 答案显然是不会的,经过测试AOP监视器是多例模式的,因此不会因为同步代码块造成不同请求线程之间的阻塞
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1300452403@qq.com