首页 专题 文章 代码 归档

【拦截器】Springboot使用拦截器限制访问频率

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有问题,该拦截器没有生效,那么极大可能的原因是你的项目中,实现/继承了WebMvcConfigurerWebMvcConfigurationSupport或其他

导致该拦截器并不被springboot识别,解决方法很简单,重写这些方法中的

类似下面的这类方法,然后添加一个拦截器即可:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    //    注册Interceptor
    registry.addInterceptor(frequentInterceptor);
}
此文阅读完毕,您可以:分享
二维码图片 扫描关注我们哟