1. 前言
拦截器和过滤器都很有用,前者针对方法访问,后者针对web访问
限制接口访问频率,我们只需要使用拦截器+注解即可!
异常方便!
2. 拦截器
@Component
@Slf4j
public class FrequentInterceptor extends HandlerInterceptorAdapter {
@Resource
RedisUtils redisUtils;
//肯定是preHandle
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//返回true就是直接通过
if (handler instanceof HandlerMethod) {//是方法
HandlerMethod handlerMethod = (HandlerMethod) handler;
String simpleName =
handlerMethod.getMethod().getDeclaringClass().getSimpleName() + "."
+ handlerMethod.getMethod().getName();
log.info("simpleName ==>> {}", simpleName);
FrequencyLimit methodAnnotation = handlerMethod.getMethodAnnotation(FrequencyLimit.class);
if (methodAnnotation == null) return true;//直接返回true,放行
boolean ok = isOk(simpleName, methodAnnotation, request);
if (!ok) {
// response
//抛出错误
request.setAttribute("filter.error", new MyException(ResultCode.VISIT_TOO_OFTEN));
request.getRequestDispatcher("/error/throw").forward(request, response);
}
return ok;
}
// return super.preHandle(request, response, handler);
return false;
}
//判断是否redis中有此记录(有的话,说明采访问了此接口,暂停访问)
public boolean isOk(String simpleName, FrequencyLimit frequencyLimit, HttpServletRequest request) {
int value = frequencyLimit.value();
if (value == 0) {//为0直接false
return false;
}
String ip = request.getRemoteAddr();
Object o = redisUtils.get(Constants.Common.KEY_FREQUENT_LIMIT + simpleName + "_" + ip);
if (o == null) {
//设置限制
redisUtils.set(Constants.Common.KEY_FREQUENT_LIMIT + simpleName + "_" + ip, "true", value);
return true;
}
return false;
}
}
主要就是结合redis,判断前N秒是否已经访问过了,如果是,则返回提示信息,没有就放行!
再结合一个注解,直接就可以在一个Controller方法上使用该注解即可限制频率。
@Documented
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FrequencyLimit {
int value() default 10;
}
3. 踩坑
如果直接加上@Component
有问题,该拦截器没有生效,那么极大可能的原因是你的项目中,实现/继承了WebMvcConfigurer
或WebMvcConfigurationSupport
或其他
导致该拦截器并不被springboot识别,解决方法很简单,重写这些方法中的
类似下面的这类方法,然后添加一个拦截器即可:
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册Interceptor
registry.addInterceptor(frequentInterceptor);
}