How does Spring Boot use Redis for API anti-brush current limiting?

Java technology stack

www.javastack.cn

Follow to read more quality articles

The demand for current limiting appears in many common scenarios:

API current limit combat

First of all, we write the annotation class AccessLimit, and use the annotation method in the method upper limit flow to be more elegant and convenient! Please click here to read how Spring Boot integrates Redis .

The three parameters respectively represent the effective time, the maximum number of visits, and whether you need to log in, which can be understood as the maximum number of visits maxCount times within seconds.

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 {
    int seconds();
    int maxCount();
    boolean needLogin() default true;
}

The idea of ​​current limiting:

  • Use the path: ip as the key and access times as the value to uniquely identify a certain user's request

  • Each time you visit, determine keywhether it exists and whether it countexceeds the limited number of visits

  • If the access exceeds the limit, it should be responsereturned msg:请求过于频繁to the front end for display

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;

@Component
public class AccessLimtInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisService 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 (null == accessLimit) {
                return true;
            }
            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            boolean needLogin = accessLimit.needLogin();

            if (needLogin) {
                //判断是否登录
            }

            String key = request.getContextPath() + ":" + request.getServletPath() + ":" + ip ;

            Integer count = redisService.get(key);

            if (null == count || -1 == count) {
                redisService.set(key, 1);
                redisService.expire(seconds);
                return true;
            }

            if (count < maxCount) {
                redisService.inCr(key);
                return true;
            }

            if (count >= maxCount) {
//                response 返回 json 请求过于频繁请稍后再试
                return false;
            }
        }

        return true;
    }
}

Register the interceptor and configure the interception path and non-interception path:

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;

// extends WebMvcConfigurerAdapter 已经废弃,java 8开始直接继承就可以
@Configuration
public class IntercepterConfig  implements WebMvcConfigurer {
    @Autowired
    private AccessLimtInterceptor accessLimtInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(accessLimtInterceptor)
                .addPathPatterns("/拦截路径")
                .excludePathPatterns("/不被拦截路径 通常为登录注册或者首页");
    }
}

ControllerYou can use annotations directly on the layer method@AccessLimit

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("test")
public class TestControler {

    @GetMapping("accessLimit")
    @AccessLimit(seconds = 3, maxCount = 10)
    public String testAccessLimit() {
        //xxxx
        return "";
    }
}

Author: to the sea

Source: cnblogs.com/haixiang/p/12012728.html

Pay attention to the Java technology stack to see more dry goods

Click the original text to get more benefits!

Guess you like

Origin blog.csdn.net/youanyyou/article/details/108543918