赞
踩
接口访问频率限制是通过在一定时间内限制用户对接口的访问次数来实现的。常见的限流算法包括令牌桶算法(Token Bucket)、漏桶算法(Leaky Bucket)、固定窗口计数器(Fixed Window Counter)和滑动窗口计数器(Sliding Window Counter)等。在Spring Boot中,我们可以通过多种方式来实现接口的限流,如使用过滤器、拦截器或者借助第三方库。
过滤器是Java Web应用中常用的一种组件,它可以在请求到达Servlet之前对请求进行预处理。通过在过滤器中实现限流逻辑,可以对所有的HTTP请求进行统一的限流控制。
拦截器是Spring框架提供的一种处理器,可以在请求处理之前和之后进行相关操作。相比于过滤器,拦截器可以更加细粒度地控制请求,适用于需要针对某些特定接口进行限流的场景。
Bucket4j是一个Java实现的高性能限流库,它支持多种限流算法,如令牌桶算法。通过使用Bucket4j,可以轻松地在Spring Boot应用中实现复杂的限流逻辑,并且它还提供了丰富的配置选项和统计功能。
首先,我们需要创建一个自定义的过滤器类,并在其中实现限流逻辑。以下是一个示例代码:
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; @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化过滤器 } @Override public 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); } @Override public 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 { @Bean public FilterRegistrationBean<RateLimitingFilter> loggingFilter(){ FilterRegistrationBean<RateLimitingFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new RateLimitingFilter()); registrationBean.addUrlPatterns("/api/*"); return registrationBean; } }
首先,我们需要创建一个自定义的拦截器类,并在其中实现限流逻辑。以下是一个示例代码:
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; @Override public 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 { @Autowired private RateLimitingInterceptor rateLimitingInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(rateLimitingInterceptor).addPathPatterns("/api/**"); } }
首先,在项目中引入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<>(); @ Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化过滤器 } @Override public 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(); } @Override public 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 { @Bean public FilterRegistrationBean<Bucket4jRateLimitingFilter> loggingFilter(){ FilterRegistrationBean<Bucket4jRateLimitingFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new Bucket4jRateLimitingFilter()); registrationBean.addUrlPatterns("/api/*"); return registrationBean; } }
根据实际业务需求选择合适的限流算法,例如:
本文详细介绍了在Spring Boot中实现接口访问频率限制的几种方法,包括基于过滤器、拦截器和第三方库Bucket4j的实现。通过合理的限流策略,可以有效防止恶意攻击,提升系统的稳定性和用户体验。在实际应用中,选择合适的限流算法和实现方式,并结合业务需求进行优化,是确保系统高效运行的关键。
希望本文能够帮助你更好地理解和实现Spring Boot中的接口访问频率限制。如果你有任何问题或建议,欢迎在评论区留言讨论。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。