api接口限流是高并发系统的重要保护措施之一
开发步骤:
1、自定义一个AccessLimit注解,主要有两个变量maxCount和second
import java.lang.annotation.*;
@Inherited
@Documented
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {
/**
* 指定时间内API请求次数
* @return
*/
int maxCount() default 5;
/**
* 请求次数的指定时间间隔(redis数据过期时间)
* @return
*/
int second() default 60;
}
2、定义一个类实现HandlerInterceptor的preHandle方法对标注解的方法进行拦截处理
@Slf4j
@Component
public class AccessLimiterInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//如果不是映射到方法直接放行
if (!(handler instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
// 是否有AccessLimit注解
if (!method.isAnnotationPresent(AccessLimit.class)){
return true;
}
AccessLimit accessLimit = method.getAnnotation(AccessLimit.class);
int maxCount = accessLimit.maxCount();
int second = accessLimit.second();
// 存储key
String key = request.getRemoteAddr() + ":" + request.getContextPath() + ":" + request.getServletPath();
// 已经访问次数
String countStr = ObjectCacheUtil.get(key);
if (Objects.isNull(countStr)){
ObjectCacheUtil.set(key, "1", second);
return true;
}
int count = Integer.parseInt(countStr);
if (count < maxCount){
ObjectCacheUtil.increment(key, 1);
return true;
}
throw new BaseException("请求次数已达上限");
}
}
3、将自定义的HandlerInterceptor交给InterceptorRegistry容器进行管理
@Configuration
public class WebWvcConfig implements WebMvcConfigurer {
@Autowired
private AccessLimiterInterceptor accessLimiterInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(accessLimiterInterceptor);
}
}
4、接口测试
@PostMapping("test")
@AccessLimit(maxCount = 2, second = 30)
public BiResponseDTO<String> test() {
return BiResponseDTO.success();
}