java使用redis接口访问频率限制
本文使用AOP与redis进行接口的访问频率限制,两个功能,可以限制两次接口访问间隔时间与几分钟内访问几次,比如,某接口3分钟内同一用户不能超过10次,并且两次访问间隔不能低于10S。废话不多说,上代码。@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documented/*** one minutes request
·
本文使用AOP与redis进行接口的访问频率限制,两个功能,可以限制两次接口访问间隔时间与几分钟内访问几次,比如,某接口3分钟内同一用户不能超过10次,并且两次访问间隔不能低于10S。废话不多说,上代码。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
* one minutes request frequency is Fifty times, exceeding the wait five minutes
* @author Administrator
*
*/
public @interface RequestLimit {
/**
* 时间范围
* @return
*/
int time () default 3600;
/**
* 时间范围内次数
* @return
*/
int count () default 4;
/**
* 访问间隔
* @return
*/
int waits () default 20;
}
@Aspect
@Component
@Order(1)
@Slf4j
public class RequestLimitAspect {
@Autowired
private RedisCacheUtil redisCache;
@Autowired
private AuthService authService;
private static final String REQ_LIMIT = "req_limit_%s_%s";
private static final String REQ_LIMIT_FREQUENCY = "req_limit_frequency_%s_%s";
/**
* 定义拦截规则:拦截com.springboot.bcode.api包下面的所有类中,有@RequestLimit Annotation注解的方法
* 。
*/
@Pointcut("@within(org.springframework.web.bind.annotation.RestController) " +
"&& @annotation(com.shimao.microservice.aspect.RequestLimit)")
public void pointcut() {
}
@Around("pointcut()")
public Object method(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
TokenAccessReq tokenAccessReq = this.getArgs(args);
ResultObject<UserIdGetRsp> resultObject = authService.getUserId(tokenAccessReq);
if (!resultObject.isSuccess()) {
throw new BusinessException(resultObject.getCode(), resultObject.getMsg());
}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod(); // 获取被拦截的方法
RequestLimit limt = method.getAnnotation(RequestLimit.class);
// No request for limt,continue processing request
if (limt == null) {
return joinPoint.proceed();
}
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
int time = limt.time();
int count = limt.count();
int waits = limt.waits();
Long userId = resultObject.getData().getUserId();
String url = request.getRequestURI();
// judge codition
//间隔限制
String key2 = String.format(REQ_LIMIT_FREQUENCY url, userId);
String frequency = redisCache.getStr(key2);
if (StringUtils.isNotBlank(frequency)) {
return returnLimit();
}
//频次限制
String key = String.format(REQ_LIMIT, url, userId);
List<String> valueList = (List<String>) redisCache.get(key);
if (CollectionUtils.isEmpty(valueList)) {
saveLimit(time, waits, key2, key, new ArrayList<>());
return joinPoint.proceed();
}
//将有效的过滤出来,过期时间在当前时间后的
valueList = valueList.stream().filter( o -> DateUtil.getDate(o).after(new Date())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(valueList) && valueList.size() >= count) {
return returnLimit();
}
saveLimit(time, waits, key2, key, valueList);
return joinPoint.proceed();
}
private void saveLimit (int time, long waits, String key2, String key, List<String> valueList) {
String limitDate = DateUtil.getDateString(DateUtil.addSeconds(new Date(), time));
valueList.add(limitDate);
redisCache.set(key, valueList, (long) time, TimeUnit.SECONDS);
redisCache.set(key2, limitDate, waits, TimeUnit.SECONDS);
}
public TokenAccessReq getArgs(Object[] args) {
if (args != null && args.length > 0) {
try {
Object[] var4 = args;
int var5 = args.length;
for(int var6 = 0; var6 < var5; ++var6) {
Object arg = var4[var6];
if (arg instanceof TokenAccessReq) {
return (TokenAccessReq) arg;
}
}
} catch (Exception var8) {
log.error("log request params error", var8);
}
return null;
} else {
return null;
}
}
/**
* 返回拒绝信息
*
* @return
* @throws IOException
*/
private String returnLimit() throws IOException {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getResponse();
PrintWriter out = response.getWriter();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=UTF-8");
out.write("{\"code\":\"8000\",\"msg\":\"busy request!\",\"timestamp\":"+ System.currentTimeMillis() +",\"data\":null,\"success\":false}");
out.flush();
out.close();
return null;
}
}
使用
@RequestLimit
@PostMapping("/doWord")
public ResultObject doWord (@RequestBody RequestBody req) {
return ResultObject.buildSuccess();
}
更多推荐
已为社区贡献1条内容
所有评论(0)