SpringBoot+Redis+custom annotations implement interface anti-brush (limit the maximum number of requests per unit time for different interfaces)

Scenes

The project built by SpringBoot needs to implement anti-brush restrictions on the open interface, and the specified number of times can be requested within a specified number of seconds for different interfaces.

For example, the following limits the interface to request at most one time per second.

Note:

Blog:
Overbearing rogue temperament blog_CSDN Blog-C#, Architecture Road, Blogger in SpringBoot

accomplish

1. Implementation idea

First, customize the annotation and add the fields of time interval and maximum number of requests.

Then the custom interceptor intercepts whether there is a custom annotation on the interception method, and if so, obtains the requested url and uses it as the key stored in redis, and the interval is used as redis

The expiration time of the key, each request is accumulated and stored in redis, and if it is judged that the maximum number of requests is exceeded within the validity period of the redis key, a response with frequent requests will be returned.

2. First, implement custom annotations

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. Then customize the interception to implement the HandlerInterceptor interface, and rewrite its preHandle method to implement the interception before the method request

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();
    }
}

Among them, RedisCache is an encapsulated tool class for operating redis

AjaxResult is the encapsulated response result entity.

Constants.CALL_TOO_OFEN is a constant class used to prompt that the request is too frequent.

The encapsulation of the above tool classes can refer to

If you follow the front-end and back-end separation version to teach you how to build the environment locally and run the project:

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

4. Then register the interceptor in 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. When using, add annotations to the interface method and specify the time and maximum number of requests

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

The above parameter setting means that the maximum number of requests within 1 second is 1.

Guess you like

Origin blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/130594444