Spring Boot 接口访问频率限制的实现详解

目录

  1. 概述
  2. 为什么需要接口访问频率限制
  3. 常见的实现方式
    • 基于过滤器的实现
    • 基于拦截器的实现
    • 基于第三方库Bucket4j的实现
  4. 实际代码示例
    • 基于过滤器实现Rate Limiting
    • 基于拦截器实现Rate Limiting
    • 使用Bucket4j实现Rate Limiting
  5. 最佳实践
    • 选择合适的限流算法
    • 优化性能
    • 记录日志和监控
  6. 总结

概述

接口访问频率限制是通过在一定时间内限制用户对接口的访问次数来实现的。常见的限流算法包括令牌桶算法(Token Bucket)、漏桶算法(Leaky Bucket)、固定窗口计数器(Fixed Window Counter)和滑动窗口计数器(Sliding Window Counter)等。在Spring Boot中,我们可以通过多种方式来实现接口的限流,如使用过滤器、拦截器或者借助第三方库。

为什么需要接口访问频率限制

  1. 防止恶意攻击:通过限制接口的访问频率,可以有效防止恶意用户或机器人频繁访问接口,导致系统资源耗尽。
  2. 提升系统稳定性:在高并发场景下,限流可以有效保护后端服务,避免因流量过大而导致系统崩溃。
  3. 提升用户体验:合理的限流可以保障所有用户都能获得较好的服务质量,避免个别用户过度使用资源。

常见的实现方式

基于过滤器的实现

过滤器是Java Web应用中常用的一种组件,它可以在请求到达Servlet之前对请求进行预处理。通过在过滤器中实现限流逻辑,可以对所有的HTTP请求进行统一的限流控制。

基于拦截器的实现

拦截器是Spring框架提供的一种处理器,可以在请求处理之前和之后进行相关操作。相比于过滤器,拦截器可以更加细粒度地控制请求,适用于需要针对某些特定接口进行限流的场景。

基于第三方库Bucket4j的实现

Bucket4j是一个Java实现的高性能限流库,它支持多种限流算法,如令牌桶算法。通过使用Bucket4j,可以轻松地在Spring Boot应用中实现复杂的限流逻辑,并且它还提供了丰富的配置选项和统计功能。

实际代码示例

基于过滤器实现Rate Limiting

首先,我们需要创建一个自定义的过滤器类,并在其中实现限流逻辑。以下是一个示例代码:

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;public class RateLimitingFilter implements Filter {private final ConcurrentMap<String, Long> requestCounts = new ConcurrentHashMap<>();private static final long ALLOWED_REQUESTS_PER_MINUTE = 60;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化过滤器}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;String clientIp = httpRequest.getRemoteAddr();long currentTimeMillis = System.currentTimeMillis();requestCounts.putIfAbsent(clientIp, currentTimeMillis);long lastRequestTime = requestCounts.get(clientIp);if (TimeUnit.MILLISECONDS.toMinutes(currentTimeMillis - lastRequestTime) < 1) {long requestCount = requestCounts.values().stream().filter(time -> TimeUnit.MILLISECONDS.toMinutes(currentTimeMillis - time) < 1).count();if (requestCount > ALLOWED_REQUESTS_PER_MINUTE) {httpResponse.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);httpResponse.getWriter().write("Too many requests");return;}}requestCounts.put(clientIp, currentTimeMillis);chain.doFilter(request, response);}@Overridepublic void destroy() {// 销毁过滤器}
}

然后,在Spring Boot应用的配置类中注册这个过滤器:

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<RateLimitingFilter> loggingFilter(){FilterRegistrationBean<RateLimitingFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new RateLimitingFilter());registrationBean.addUrlPatterns("/api/*");return registrationBean;}
}

基于拦截器实现Rate Limiting

首先,我们需要创建一个自定义的拦截器类,并在其中实现限流逻辑。以下是一个示例代码:

import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;public class RateLimitingInterceptor implements HandlerInterceptor {private final ConcurrentMap<String, Long> requestCounts = new ConcurrentHashMap<>();private static final long ALLOWED_REQUESTS_PER_MINUTE = 60;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String clientIp = request.getRemoteAddr();long currentTimeMillis = System.currentTimeMillis();requestCounts.putIfAbsent(clientIp, currentTimeMillis);long lastRequestTime = requestCounts.get(clientIp);if (TimeUnit.MILLISECONDS.toMinutes(currentTimeMillis - lastRequestTime) < 1) {long requestCount = requestCounts.values().stream().filter(time -> TimeUnit.MILLISECONDS.toMinutes(currentTimeMillis - time) < 1).count();if (requestCount > ALLOWED_REQUESTS_PER_MINUTE) {response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);response.getWriter().write("Too many requests");return false;}}requestCounts.put(clientIp, currentTimeMillis);return true;}
}

然后,在Spring Boot应用的配置类中注册这个拦截器:

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;@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate RateLimitingInterceptor rateLimitingInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(rateLimitingInterceptor).addPathPatterns("/api/**");}
}

使用Bucket4j实现Rate Limiting

首先,在项目中引入Bucket4j依赖:

<dependency><groupId>com.github.vladimir-bukhtoyarov</groupId><artifactId>bucket4j-core</artifactId><version>7.0.0</version>
</dependency>

然后,创建一个自定义的过滤器类,并在其中实现限流逻辑:

import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Bucket4j;
import io.github.bucket4j.Refill;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;public class Bucket4jRateLimitingFilter implements Filter {private final ConcurrentMap<String, Bucket> buckets = new ConcurrentHashMap<>();@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化过滤器}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;String clientIp = httpRequest.getRemoteAddr();Bucket bucket = buckets.computeIfAbsent(clientIp, this::newBucket);if (bucket.tryConsume(1)) {chain.doFilter(request, response);} else {httpResponse.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);httpResponse.getWriter().write("Too many requests");}}private Bucket newBucket(String clientIp) {return Bucket4j.builder().addLimit(Bandwidth.classic(60, Refill.greedy(60, Duration.ofMinutes(1)))).build();}@Overridepublic void destroy() {// 销毁过滤器}
}

然后,在Spring Boot应用的配置类中注册这个过滤器:

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<Bucket4jRateLimitingFilter> loggingFilter(){FilterRegistrationBean<Bucket4jRateLimitingFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new Bucket4jRateLimitingFilter());registrationBean.addUrlPatterns("/api/*");return registrationBean;}
}

最佳实践

选择合适的限流算法

根据实际业务需求选择合适的限流算法,例如:

  • 令牌桶算法:适用于需要平滑突发流量的场景。
  • 漏桶算法:适用于需要严格控制流量的场景。
  • 固定窗口计数器:适用于对简单限流要求的场景。
  • 滑动窗口计数器:适用于需要精确控制限流的场景。

优化性能

  • 减少锁竞争:在高并发环境下,尽量减少锁的使用,可以采用无锁数据结构或者线程安全的数据结构。
  • 缓存结果:对于频繁访问的数据,可以考虑进行缓存,减少数据库查询的次数。
  • 异步处理:对于耗时的操作,可以考虑采用异步处理,提高系统的响应速度。

记录日志和监控

  • 记录访问日志:记录每次接口访问的详细信息,包括请求时间、IP地址、请求路径等。
  • 监控限流情况:对限流情况进行监控,及时发现和处理异常流量。
  • 报警机制:设置限流报警机制,当流量超过预设阈值时,及时报警。

总结

本文详细介绍了在Spring Boot中实现接口访问频率限制的几种方法,包括基于过滤器、拦截器和第三方库Bucket4j的实现。通过合理的限流策略,可以有效防止恶意攻击,提升系统的稳定性和用户体验。在实际应用中,选择合适的限流算法和实现方式,并结合业务需求进行优化,是确保系统高效运行的关键。

希望本文能够帮助你更好地理解和实现Spring Boot中的接口访问频率限制。如果你有任何问题或建议,欢迎在评论区留言讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/48149.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Manticore Search(es轻量级替代)

概念&#xff1a; Manticore Search 是一个使用 C 开发的高性能搜索引擎&#xff0c;创建于 2017 年&#xff0c;其前身是 Sphinx Search 。Manticore Search 充分利用了 Sphinx&#xff0c;显着改进了它的功能&#xff0c;修复了数百个错误&#xff0c;几乎完全重写了代码并保…

MySQL第四次作业

1.修改student表中年龄字段属性&#xff0c;数据类型由int改变为smallint 2.为course表中cno课程学号设置索引&#xff0c;并查看索引 &#xff08;3&#xff09;为SC表建立按学号(sno)和课程号(cno)组合的升序的主键索引&#xff0c;索引名为SC_INDEX &#xff08;4&#xff0…

PHP框架详解-symfony

一、介绍 Symfony是一个用于构建Web应用程序的PHP框架。它是一个开源框架,由Fabien Potencier于2005年创建。 Symfony框架具有许多特性和优势,以下是一些重要的特性: 可重复使用的组件:Symfony框架基于一系列可重复使用的组件,这些组件可以独立于框架使用,并且可以被其…

mysql对数据库的增删改

目录 DML语句&#xff1a; 增加数据&#xff08;insert语句&#xff09; 增加数据&#xff08;insert into select&#xff09; 修改数据&#xff08;update语句&#xff09; 【where 子句条件】 删除数据&#xff08;delete语句&#xff09; 删除数据&#xff08;trunca…

Spring, Spring Boot 和Spring MVC的关系以及区别

一、Spring 简单来说, Spring 是一个开发应用框架&#xff0c;主打轻量级、一站式、模块化&#xff0c;其目的是用于简化企业级应用程序开发。 Spring 的主要功能&#xff1a;管理对象&#xff0c;以及对象之间的依赖关系&#xff0c;面向切面编程&#xff0c;数据库事务管理, …

NO.1 Hadoop概述

1.1 Hadoop是什么 1.2 Hadoop优势 1.3 Hadoop组成 1.3.1 HDFS架构概述 1.3.2 YARN架构概述 1.3.3 MapReduce架构概述 1.3.4 HDFS、YARN、MapReduce三者关系 1.4 大数据技术生态体系 1.5 推荐系统框架图

数据结构C++——优先队列

文章目录 一、定义二、ADT三、优先队列的描述3.1 线性表3.2 堆3.2.1 最大堆的ADT3.2.2 最大堆的插入3.2.3 最大堆的删除3.2.4 最大堆的初始化3.3 左高树 LT3.3.1 高度优先左高树HBLT3.3.2 重量优先左高树WBLT3.3.3 最大HBLT的插入3.3.4 最大HBLT的删除3.3.5 合并两棵最大HBLT3.…

【Linux】yum的认识与简单配置

今天来初步认识一下yum——Linux下软件包管理器。 既然说到Linux下软件包管理器&#xff0c;那我们不妨来先谈论一下什么是软件包的概念。 1. 什么是软件包&#xff1f; 软件的下载需要源代码编译链接之后生成可执行文件进行运行。无论是Windows系统下还是Linux系统下&#x…

QT总结——图标显示坑

最近写代码遇到一个神仙大坑&#xff0c;我都怀疑我软件是不是坏了&#xff0c;这里记录一下。 写qt工程的时候我们一般会设置图标&#xff0c;这个图标是窗体的图标同时也是任务栏的图标&#xff0c;但是我发现生成的exe没有图标&#xff0c;这个时候就想着给他加一个图标&…

AI学习记录 - 激活函数的作用

试验&#xff0c;通过在线性公式加入激活函数&#xff0c;可以拟合复杂的情况&#xff08;使用react实现&#xff0c;原创&#xff09; 结论:1、线性函数的叠加&#xff0c;无论叠加多少次&#xff0c;都是线性的 如下图 示例代码 线性代码&#xff0c;使用ykxb的方式&…

【BUG】已解决:ValueError: All arrays must be of the same length

ValueError: All arrays must be of the same length 目录 ValueError: All arrays must be of the same length 【常见模块错误】 【解决方案】 问题原因 解决方法 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&…

Python爬虫实战案例(爬取图片)

爬取图片的信息 爬取图片与爬取文本内容相似&#xff0c;只是需要加上图片的url&#xff0c;并且在查找图片位置的时候需要带上图片的属性。 这里选取了一个4K高清的壁纸网站&#xff08;彼岸壁纸https://pic.netbian.com&#xff09;进行爬取。 具体步骤如下&#xff1a; …

[Python][Python入门]详细讲解

目录 0.铺垫1.常量和表达式2.变量3.变量的类型1.整数2.浮点数3.字符串4.布尔 4.动态类型特性5.注释∞.积累 0.铺垫 Python中&#xff0c;一个语句写完了之后&#xff0c;可以加上分号&#xff0c;也可以不加 通常情况下都是不加的&#xff0c;如果加了&#xff0c;也不算错如果…

Ubuntu-文件管理器中鼠标右键添加文本文件

文件管理器中鼠标右键添加文本文件 一、概述二、步骤 一、概述 Ubuntu在文管右键发现没有创建文本文件的菜单&#xff0c; 期望如下所示&#xff0c;这样的操作非常简单 二、步骤 找到模板文件夹 在模板文件夹&#xff0c;创建自己想要的文件就好啦 这个也是支持放文件夹去…

【C++】学习笔记——哈希_1

文章目录 十八、哈希1. unordered系列关联式容器2. 底层结构哈希函数哈希冲突 未完待续 十八、哈希 1. unordered系列关联式容器 在C11中&#xff0c;STL又提供了4个unordered系列的关联式容器&#xff0c;这四个容器与红黑树结构的关联式容器使用方式基本类似&#xff0c;只…

Linux云计算 |【第二阶段】AUTOMATION-DAY1

主要内容&#xff1a; 版本控制&#xff08;集中式、分布式&#xff09;、Git基础&#xff08;服务端、客户端部署&#xff0c;基础命令操作、文档版本管理&#xff09;、Git进阶&#xff08;数据恢复、分支、冲突管理&#xff09; 一、版本控制概念 版本控制是一种记录文件变…

iterm2工具的使用|MAC电脑终端实现分屏|iterm2开启滚动操作

iterm2 工具概括 iTerm2 是一款非常强大的终端工具。 iTerm2 最初是为 macOS 开发的,但也有 Windows 、Linux 发行版&#xff08;Ubuntu、centos…&#xff09;可用。 应用场景 Mac操作系统中想实现终端分屏 iterm2 工具特点 多标签和分屏: 可以在同一个窗口中打开多个标签…

C基础(学习)2024.7.23

Linux基本命令&#xff0c;vi编译器的使用&#xff0c;简单的编程步骤&#xff0c;程序语言&#xff0c;gcc编译器编译过程&#xff0c;进制转换相关知识可以查看文档http://t.csdnimg.cn/CmqhC 数值表示&#xff0c;词法符号&#xff0c;变量&#xff0c;常量相关知识可以查看…

.mp4格式的视频为何不能通过video标签在chrome浏览器中播放?

chrome浏览器目前只支持编解码格式为H264格式的视频&#xff0c;如果某个.mp4后缀的视频不能在chrome浏览器中播放&#xff0c;多半是这个视频的编码格式不是H264的&#xff01; 1、可以通过ffmpeg工具查看当前视频的编码格式&#xff1a; ffprobe -v error -select_streams v…

JS_plus.key.addEventListener监听键盘按键

官方文档&#xff1a;https://www.html5plus.org/doc/zh_cn/key.html 监听事件 plus.key.addEventListener(keydown, e > {console.log("keydown: "e.keyCode) }) plus.key.addEventListener(keyup, e > {console.log("keyup: "e.keyCode) })移除事…