SpringBoot+Redis+自定义注解实现接口防刷(限制不同接口单位时间内最大请求次数)

场景

SpringBoot搭建的项目需要对开放的接口进行防刷限制,不同接口指定多少秒内可以请求指定次数。

比如下方限制接口一秒内最多请求一次。

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

实现

1、实现思路

首先自定义注解,添加时间区间和最大请求次数字段。

然后自定义拦截器拦截方法上面是否有自定义的注解,如果有则获取请求的url,并作为redis中存储的key,区间区间即作为redis

的key的过期时间,每次请求累加次数并存储到redis中,判断在redis的key有效期内超过最大请求次数,则返回请求频繁的响应。

2、首先自定义注解实现

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
    /**
     * 秒数时间区间(多少秒内)
     * @return
     */
    int seconds();
    /**
     * 最大请求次数
     * @return
     */
    int maxCount();
}

3、然后自定义拦截实现HandlerInterceptor接口,并重写其preHandle方法,实现方法请求前的拦截

import com.alibaba.fastjson.JSON;
import com.badao.demo.common.AjaxResult;
import com.badao.demo.constant.Constants;
import com.badao.demo.utils.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;

@Component
public class FangshuaInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisCache redisService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断请求是否属于方法的请求
        if(handler instanceof HandlerMethod){
            HandlerMethod hm = (HandlerMethod) handler;
            //获取方法中的注解,看是否有该注解
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if(accessLimit == null){
                return true;
            }
            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            //获取请求的Url作为redis中存储的key
            String key = request.getRequestURI();
            //从redis中获取用户访问的次数
            Integer count = redisService.getCacheObject(key);
            if(count == null){
                //第一次访问
                redisService.setCacheObject(key,1,seconds, TimeUnit.SECONDS);
            }else if(count < maxCount){
                //加1
                count+=1;
                redisService.setCacheObject(key,count,seconds, TimeUnit.SECONDS);
            }else{
                //超出访问次数,则渲染响应结果
                render(response);
                return false;
            }
        }
        return true;
    }

    /**
     * 接口渲染
     * @param response
     * @throws Exception
     */
    private void render(HttpServletResponse response)throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        String str  = JSON.toJSONString(AjaxResult.error(Constants.CALL_TOO_OFEN));
        out.write(str.getBytes("UTF-8"));
        out.flush();
        out.close();
    }
}

其中RedisCache是封装的操作redis的工具类

AjaxResult是封装的响应结果实体。

Constants.CALL_TOO_OFEN是常量类用来提示请求太频繁。

以上工具类的封装可以参考

若依前后端分离版手把手教你本地搭建环境并运行项目:

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662 

4、然后将intercepter注册到springboot中

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 把intercepror 注册到springboot中
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private FangshuaInterceptor interceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor);
    }
}

5、使用时在接口方法上添加注解并指定时间和最大请求次数

    @AccessLimit(seconds = 1,maxCount = 1)
    @GetMapping("/test")
    public AjaxResult test(@RequestParam("mineApiCode") String mineApiCode)

上面参数设置就是1秒内最大请求次数为1次。

猜你喜欢

转载自blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/130594444