Skip to content

Instantly share code, notes, and snippets.

@vernetto
Created October 26, 2023 08:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vernetto/c4a49ad1eb4c798bfe4ec4560571b311 to your computer and use it in GitHub Desktop.
Save vernetto/c4a49ad1eb4c798bfe4ec4560571b311 to your computer and use it in GitHub Desktop.
throttling
in Spring Framework is there a way to throttle HTTP requests from a specific user?
ChatGPT
Yes, in the Spring Framework, you can throttle HTTP requests from a specific user using various techniques. One of the popular ways is to use Spring Cloud Gateway, but for simple applications, you might not need such a sophisticated solution. Here's a breakdown of some methods:
Spring Cloud Gateway Ratelimiter: If you're using Spring Cloud Gateway, there's built-in support for request rate limiting using Redis. You can create route-specific rate limiters and key the rate limit by user or other request attributes.
Spring Security with a custom filter: If you're using Spring Security, you can add a custom filter that checks the number of requests from a user within a specific time frame.
Third-party libraries: Libraries like Bucket4j or Resilience4j offer rate limiting and can be integrated into Spring applications.
Here's a simple example using Spring Security and a custom filter:
java
@Component
public class RateLimitFilter extends OncePerRequestFilter {
private static final int MAX_REQUESTS_PER_MINUTE = 10; // You can adjust this value
private final Map<String, SimpleRateLimiter> limiterCache = new ConcurrentHashMap<>();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String userKey = extractUserKey(request); // You need to define how you extract the user's unique key
limiterCache.putIfAbsent(userKey, new SimpleRateLimiter(MAX_REQUESTS_PER_MINUTE));
SimpleRateLimiter rateLimiter = limiterCache.get(userKey);
if (rateLimiter.tryAcquire()) {
filterChain.doFilter(request, response);
} else {
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
response.getWriter().write("Too many requests");
}
}
private String extractUserKey(HttpServletRequest request) {
// This can be an authenticated user's username, session ID, IP address, etc.
return request.getRemoteAddr();
}
}
class SimpleRateLimiter {
private final int maxRequestPerMinute;
private final Map<Long, Integer> requestCountsPerMinute = new HashMap<>();
public SimpleRateLimiter(int maxRequestPerMinute) {
this.maxRequestPerMinute = maxRequestPerMinute;
}
synchronized boolean tryAcquire() {
long currentMinute = Instant.now().getEpochSecond() / 60;
requestCountsPerMinute.putIfAbsent(currentMinute, 0);
if (requestCountsPerMinute.get(currentMinute) < maxRequestPerMinute) {
requestCountsPerMinute.computeIfPresent(currentMinute, (key, val) -> val + 1);
return true;
}
// Clean up old entries to prevent memory leaks
requestCountsPerMinute.entrySet().removeIf(entry -> entry.getKey() < currentMinute);
return false;
}
}
This is a rudimentary example, and there are many optimizations and improvements you can make. In a production scenario, you'd also want to consider using a distributed rate limiter (like the one Spring Cloud Gateway offers with Redis) to handle clustered deployments.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment