发布于2026-04-19 阅读(0)
扫一扫,手机访问

本文介绍在 Spring Boot 应用中基于用户身份(如用户名或用户 ID)实现独立、隔离的请求速率限制,避免全局限流导致多用户相互干扰,涵盖唯一标识设计、缓存存储策略与核心代码实现。
本文介绍在 Spring Boot 应用中基于用户身份(如用户名或用户 ID)实现独立、隔离的请求速率限制,避免全局限流导致多用户相互干扰,涵盖唯一标识设计、缓存存储策略与核心代码实现。
在典型的 Spring Boot 限流实践中,若仅使用 @RateLimiter(Spring Cloud Gateway)、Resilience4j 或自定义拦截器配合内存计数器,往往默认以请求路径(如 /api/search)为维度进行统计——这会导致所有用户共享同一计数桶,即用户 A 触发 5 次/分钟上限后,用户 B 的首次请求也会被拒绝。这显然违背“按用户限流”的业务需求(例如:VIP 用户配额更高、普通用户需严格管控、防爬虫需绑定账号行为等)。
要实现用户级独立限流,关键在于两点:
✅ 唯一键(Key)必须携带用户上下文;
✅ 计数状态需支持高并发读写与自动过期。
使用 RedisTemplate 结合 StringRedisTemplate 实现带 TTL 的原子计数,是最常用且生产就绪的方案。以下为完整示例(基于 Spring Boot 3.x + Spring Data Redis):
@Component
public class UserRateLimiter {
private final StringRedisTemplate redisTemplate;
private static final String RATE_LIMIT_KEY_PREFIX = "rate:limit:user:";
public UserRateLimiter(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 检查当前用户是否允许访问
* @param userId 用户唯一标识(建议使用 long 类型 ID 或 UUID,避免敏感信息如明文 username)
* @param maxRequests 允许最大请求数
* @param windowSeconds 时间窗口(秒)
* @return true 表示允许,false 表示已被限流
*/
public boolean tryAcquire(String userId, int maxRequests, int windowSeconds) {
String key = RATE_LIMIT_KEY_PREFIX + userId;
Long currentTime = System.currentTimeMillis();
// 使用 Redis Lua 脚本保证原子性:先递增,再设置过期(仅首次递增时生效)
String script = """
local current = tonumber(redis.call('INCR', KEYS[1]))
if current == 1 then
redis.call('EXPIRE', KEYS[1], ARGV[1])
end
return current
""";
Long count = redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(key),
String.valueOf(windowSeconds)
);
return count != null && count <= maxRequests;
}
}在 Web 层(如 @RestControllerAdvice 或 HandlerInterceptor)中调用该组件:
@Component
public class RateLimitInterceptor implements HandlerInterceptor {
private final UserRateLimiter rateLimiter;
private final UserService userService; // 假设你有获取当前登录用户的服务
public RateLimitInterceptor(UserRateLimiter rateLimiter, UserService userService) {
this.rateLimiter = rateLimiter;
this.userService = userService;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String userId = (auth != null && auth.getPrincipal() instanceof UserDetails userDetails)
? String.valueOf(userDetails.getUsername()) // 或更优:userDetails.getId()
: "anonymous";
// 对 /api/products/search 接口启用 5 次/60 秒限流
if ("/api/products/search".equals(request.getRequestURI())
&& !rateLimiter.tryAcquire(userId, 5, 60)) {
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"error\":\"Rate limit exceeded for this user\"}");
return false;
}
return true;
}
}通过以上设计,每位用户拥有完全独立的计数桶,互不影响。系统既保障了资源公平性,又支持灵活配额管理(如通过数据库动态加载各用户 maxRequests),是微服务架构下用户级限流的标准实践路径。
下一篇:海棠文学城官网入口及网址汇总
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8