首页/

SpringBoot接口频率限制(每个IP限制)

评论 (0)访问 (366)分类:破碎代码发布时间:

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

代码

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface HasApiLimit {
    /**
     * 时间范围(分钟)
     */
    int seconds();
    /**
     * 限制的次数
     */
    int maxCount();
}
@Aspect
@Component
public class ApiLimit {
    /**
     * 定义一个切点(通过注解)
     */
    @Pointcut("@annotation(com.blog.aop.has.HasApiLimit)")
    public void HasApiLimit() {
    }
    /**
     * Aop切面方法
     *
     * @param joinPoint 切点
     */
    @Before("HasApiLimit()")
    public void before(JoinPoint joinPoint) {
        //获取当前请求的方法上的注解中设置的值
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //反射获取当前被调用的方法
        Method method = signature.getMethod();
        //获取方法中的注解,看是否有该注解
        HasApiLimit hasApiLimit = method.getDeclaredAnnotation(HasApiLimit.class);
        int seconds = hasApiLimit.seconds();
        int maxCount = hasApiLimit.maxCount();
        //获取请求相关信息
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String ip = getIpAddr(request);
        String api = request.getRequestURI();
        //拼接redis key
        String key = "HasApiLimit:" + ip + ":" + api;
        //判断key是否存在,如果不存在,则说明是第一次访问
        if (!RedisUtils.hasKey(key)) {
            RedisUtils.set(key, 1, seconds, TimeUnit.MINUTES);
        } else {
            //key存在,则获取当前访问次数
            int count = Integer.parseInt(String.valueOf(RedisUtils.get(key)));
            if (count >= maxCount) {
                //超过了限制次数,返回错误信息
                throw new BusinessException("使用频率过高," + seconds + "分钟后再试");
            } else {
                RedisUtils.increment(key, 1);
            }
        }
    }
    /**
     * 获取真实IP地址
     *
     * @param request HttpServletRequest
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

使用方法

@HasApiLimit(seconds = 3, maxCount = 1)
@HasRoleAuth("api:comments:create")
@PostMapping("/create")
public R<?> create(@RequestBody CommentBo commentBo) {
    commentService.create(commentBo);
    return R.ok(null, "评论成功");
}

注意事项

要获取真实的IP地址

因此需要在Nginx或Apache等Web服务器中配置反向代理

可以在Web服务器中添加如下配置:

location / {
    proxy_pass http://127.0.0.1:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

点赞(0)

收藏(0)

打赏

发布于

发表评论- Comments

您必须登录注册发表评论

一个神奇的博客

保 洁 阿 姨

拥有60+年的前端设计经验

动态数量

闲言杂语

运行天数

访 客 量