当前位置: 代码网 > it编程>编程语言>Java > SpringBoot通过拦截器实现接口限流的两种方案

SpringBoot通过拦截器实现接口限流的两种方案

2025年10月11日 Java 我要评论
在spring boot中,可以通过自定义拦截器(interceptor)结合redis或内存计数器实现接口限流。以下是两种典型实现方式及代码示例:​方案一:基于redis + lua脚本的分布式限流

在spring boot中,可以通过自定义拦截器(interceptor)结合redis或内存计数器实现接口限流。以下是两种典型实现方式及代码示例:

​方案一:基于redis + lua脚本的分布式限流​

​核心逻辑​

  1. redis配置​:使用lua脚本保证原子性操作(计数+过期时间设置)。
  2. 拦截器​:拦截请求,通过redis统计ip或用户维度的访问次数。
  3. 注册拦截器​:指定拦截路径和排除路径。

​代码实现​

1. redis配置类

@configuration
public class redisconfig {
    @bean
    public redistemplate<string, object> redistemplate(redisconnectionfactory factory) {
        redistemplate<string, object> template = new redistemplate<>();
        template.setconnectionfactory(factory);
        template.setkeyserializer(new stringredisserializer());
        template.setvalueserializer(new genericjackson2jsonredisserializer());
        return template;
    }

    @bean
    public defaultredisscript<long> ratelimitscript() {
        defaultredisscript<long> script = new defaultredisscript<>();
        script.setscripttext(
            "local key = keys[1]\n" +
            "local limit = tonumber(argv[1])\n" +
            "local expire = tonumber(argv[2])\n" +
            "local current = redis.call('incr', key)\n" +
            "if current == 1 then\n" +
            "    redis.call('expire', key, expire)\n" +
            "end\n" +
            "return current > limit and 1 or 0"
        );
        script.setresulttype(long.class);
        return script;
    }
}

2. 限流拦截器

@component
public class ratelimitinterceptor implements handlerinterceptor {
    @autowired
    private redistemplate<string, object> redistemplate;
    @autowired
    private defaultredisscript<long> ratelimitscript;

    private static final int default_limit = 60; // 每分钟60次
    private static final int default_timeout = 60; // 60秒过期

    @override
    public boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) throws ioexception {
        string ip = request.getremoteaddr();
        string uri = request.getrequesturi();
        string key = "rate_limit:" + ip + ":" + uri.split("/")[1]; // 按接口前缀分组

        long result = redistemplate.execute(
            ratelimitscript,
            collections.singletonlist(key),
            default_limit, default_timeout
        );

        if (result != null && result == 1) {
            response.setstatus(httpstatus.too_many_requests.value());
            response.getwriter().write("too many requests");
            return false;
        }
        return true;
    }
}

3. 注册拦截器

@configuration
public class webconfig implements webmvcconfigurer {
    @autowired
    private ratelimitinterceptor ratelimitinterceptor;

    @override
    public void addinterceptors(interceptorregistry registry) {
        registry.addinterceptor(ratelimitinterceptor)
            .addpathpatterns("/api/**")
            .excludepathpatterns("/api/login");
    }
}

​方案二:基于内存计数器的单机限流​

​核心逻辑​

  1. 拦截器​:使用concurrenthashmap存储ip和访问时间戳。
  2. 滑动窗口​:统计1分钟内的请求数,超限则拒绝。

​代码实现​

public class ratelimitinginterceptor implements handlerinterceptor {
    private final concurrentmap<string, long> requestcounts = new concurrenthashmap<>();
    private static final long allowed_requests_per_minute = 60;

    @override
    public boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) throws exception {
        string clientip = request.getremoteaddr();
        long currenttime = system.currenttimemillis();

        // 清理过期请求
        requestcounts.entryset().removeif(entry -> 
            currenttime - entry.getvalue() > timeunit.minutes.tomillis(1)
        );

        // 统计当前窗口请求数
        long count = requestcounts.values().stream()
            .filter(timestamp -> currenttime - timestamp < timeunit.minutes.tomillis(1))
            .count();

        if (count >= allowed_requests_per_minute) {
            response.setstatus(httpservletresponse.sc_too_many_requests);
            response.getwriter().write("请求过于频繁");
            return false;
        }

        requestcounts.put(clientip, currenttime);
        return true;
    }
}

​关键对比与选择建议​

方案适用场景优点缺点
redis + lua分布式环境,高精度限流原子性操作,支持分布式,可动态调整参数依赖redis,网络开销较大
内存计数器单机环境,简单场景无外部依赖,实现简单不支持分布式,重启后数据丢失

扩展建议​:

  • 动态配置​:将限流参数(如default_limit)改为从配置中心读取。
  • 注解化​:结合自定义注解(如@ratelimit)实现更灵活的限流规则。

两种方案均能有效实现接口限流,根据项目需求选择即可。

到此这篇关于springboot通过拦截器实现接口限流的两种方案的文章就介绍到这了,更多相关springboot拦截器接口限流内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com