























ConcurrentHashMap:
doFilter(),在请求前检查是否被封禁,在请求后检查响应状态码,统计404次数import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; @WebFilter(urlPatterns = "/*") public class RateLimitFilter implements Filter { private static class IpStats { int requestCount = 0; int error404Count = 0; long lastResetTime = System.currentTimeMillis(); } // 存储IP的请求统计信息 private final ConcurrentHashMap<String, IpStats> ipStatsMap = new ConcurrentHashMap<>(); // 存储被封禁的IP及其解封时间 private final ConcurrentHashMap<String, Long> blackListMap = new ConcurrentHashMap<>(); // 配置参数 private static final int MAX_REQUESTS_PER_MINUTE = 300; private static final int MAX_404_COUNT = 300; private static final long BLOCK_TIME_MILLIS = 30 * 60 * 1000; // 30分钟 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String ip = request.getRemoteAddr(); long currentTime = System.currentTimeMillis(); // 检查是否被封禁 Long blockUntil = blackListMap.get(ip); if (blockUntil != null && blockUntil > currentTime) { ((HttpServletResponse) response).setStatus(429); // 太多请求 response.getWriter().write("访问受限,请稍后重试。"); return; } else if (blockUntil != null && blockUntil <= currentTime) { // 解封 blackListMap.remove(ip); } // 统计请求信息 IpStats stats = ipStatsMap.computeIfAbsent(ip, k -> new IpStats()); // 存在跨分钟的情况,重置统计 if (currentTime - stats.lastResetTime > 60 * 1000) { stats.requestCount = 0; stats.error404Count = 0; stats.lastResetTime = currentTime; } // 请求计数 stats.requestCount++; ipStatsMap.put(ip, stats); // 处理请求 // 使用自定义Response包装器捕获状态码 StatusCaptureResponseWrapper wrappedResponse = new StatusCaptureResponseWrapper((HttpServletResponse) response); chain.doFilter(request, wrappedResponse); // 判断响应状态码 if (wrappedResponse.getStatus() == 404) { stats.error404Count++; } // 超过404阈值,加入黑名单 if (stats.error404Count >= MAX_404_COUNT) { blackListMap.put(ip, currentTime + BLOCK_TIME_MILLIS); // 可选: 清理统计数据 ipStatsMap.remove(ip); } } /** * 自定义ResponseWrapper,用于捕获状态码 */ private static class StatusCaptureResponseWrapper extends HttpServletResponseWrapper { private int httpStatus = 200; public StatusCaptureResponseWrapper(HttpServletResponse response) { super(response); } @Override public void setStatus(int sc) { super.setStatus(sc); this.httpStatus = sc; } @Override public void sendError(int sc) throws IOException { super.sendError(sc); this.httpStatus = sc; } @Override public void sendError(int sc, String msg) throws IOException { super.sendError(sc, msg); this.httpStatus = sc; }public int getStatus() { return this.httpStatus; } } }
Filter需要添加到Spring Boot中,可以通过@WebFilter注解,或者在配置类中注册。Filter方案示例,适合单实例部署。此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。