通过Guava实现ip限流访问
一分钟内某个ip请求制定接口超过10次,则禁止该ip 10分钟内不能访问,通过Guava实现一个拦截器,拦截指定接口来处理
mport com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class IpAccessLimit { private final Cache<String, AtomicInteger> ipRequestCounts; private final Cache<String, Boolean> bannedIps; public IpAccessLimit() { // 设置缓存过期时间为1分钟 this.ipRequestCounts = CacheBuilder.newBuilder() .expireAfterWrite(1, TimeUnit.MINUTES) .build(); // 设置禁止访问的缓存过期时间为10分钟 this.bannedIps = CacheBuilder.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .build(); } /** * 检查IP是否可以访问 * * @param ip IP地址 * @return 如果可以访问返回true,否则返回false */ // public boolean canAccess2(String ip) { // RateLimiter rateLimiter = ipRateLimiters.getIfPresent(ip); // if (rateLimiter == null) { // // 初始化新的限流器,每秒最多允许10次请求 // rateLimiter = RateLimiter.create(10.0/60.0); // ipRateLimiters.put(ip, rateLimiter); // } // return rateLimiter.tryAcquire(); // } /** * 检查IP是否可以访问 * * @param ip IP地址 * @return 如果可以访问返回true,否则返回false */ public boolean canAccess(String ip) { // 检查是否在禁止访问列表中 if (bannedIps.getIfPresent(ip) != null) { return false; } AtomicInteger requestCount = ipRequestCounts.getIfPresent(ip); if (requestCount == null) { requestCount = new AtomicInteger(0); ipRequestCounts.put(ip, requestCount); } int count = requestCount.incrementAndGet(); // 如果当前分钟内的请求次数超过10次 if (count > 10) { // 将该IP加入到禁止访问列表中 bannedIps.put(ip, true); return false; } return true; } }
mport javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.regex.Pattern; public class IpAccessFilter implements Filter { private static final IpAccessLimit ipAccessLimit = new IpAccessLimit(); protected final Logger log = LoggerFactory.getLogger(IpAccessFilter.class); private Pattern limitedUrlPattern; @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化需要限制的URL模式 limitedUrlPattern = Pattern.compile(".*LoginAction\\.action$"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; // 将 ServletResponse 转换为 HttpServletResponse HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; String IPAddr = Browser.getIpAddr(request); String requestURI = request.getRequestURI(); // 只对特定的URL进行访问次数限制 if (limitedUrlPattern.matcher(requestURI).matches()) { if (ipAccessLimit.canAccess(IPAddr)) { filterChain.doFilter(servletRequest, servletResponse); } else { log.error("Too many requests from this IP address: {}",IPAddr); // 处理超出访问次数的情况,例如返回429 Too Many Requests状态码 httpResponse.setStatus(429); httpResponse.getWriter().write("Too many requests, please try again later!"); } } else { // 对其他URL不做限制,直接放行 filterChain.doFilter(request, servletResponse); } } @Override public void destroy() { } }