SpringBoot 接口限流 + 幂等企业级组合实战,彻底防重、防刷、防打爆
·
SpringBoot 接口限流 + 幂等企业级组合实战,彻底防重、防刷、防打爆
一、为什么必须「限流 + 幂等」组合使用?
在上一篇《SpringBoot AOP+Redis 实现接口幂等》中,我们解决了 重复提交、请求重试、多点重试 导致的数据重复问题。
但幂等只能解决 “重复请求结果一致”,无法解决高频恶意请求、瞬间打爆接口、DDOS 刷接口问题。
真实生产痛点
-
只做幂等不做限流
黑客 / 脚本一秒钟刷几十次接口,虽然不会产生脏数据,但会耗尽服务线程、打满 Redis、拖垮整个系统。
-
只做限流不做幂等
突发网络重试、网关重试、用户连点,依然会产生重复订单、重复扣款。
企业级标准架构
限流在前、幂等在后
- 限流:保护系统(防崩、防刷、防高并发)
- 幂等:保护数据(防重、防脏、防错乱)
两大组件组合,才是生产环境真正的接口安全护盾。
二、技术方案选型
限流算法选型:令牌桶算法
相比固定窗口、滑动窗口:
- 令牌桶 允许突发流量,适合秒杀、活动场景
- 限流平滑、不会出现临界值突刺
- 企业级微服务最主流方案
整体架构
- 基于 Redis + AOP + 自定义双注解
- 单机、分布式集群 全部支持
- 接口粒度精细化控制:不同接口不同限流阈值
- 与之前幂等框架完全兼容、无缝叠加
三、实现思路(企业级流程)
- 请求进入接口,先经过限流拦截
- 超出 QPS 直接拦截,返回「系统繁忙」
- 限流通过后,进入 幂等 Token 校验
- 重复请求直接拦截
- 全部校验通过,执行业务逻辑
顺序不能乱:先限流、后幂等!
四、完整代码实战(可直接上线)
4.1 新增限流自定义注解
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {
/**
* 限流key前缀
*/
String prefix() default "rate_limit:";
/**
* 限流时间窗口 单位秒
*/
int time() default 1;
/**
* 最大请求次数
*/
int count() default 10;
/**
* 提示语
*/
String msg() default "请求过于频繁,请稍后再试";
}
4.2 Redis 限流工具类(令牌桶思想 + 计数器实现)
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
@Component
public class RateLimitUtil {
@Resource
<String, Object> redisTemplate;
/**
* Lua脚本:原子限流
* key=限流key
* 1.不存在则初始化=1
* 2.超过阈值返回0
* 3.未超过则自增+1
*/
private static final String LIMIT_SCRIPT =
"local key = KEYS[1] " +
"local limit = tonumber(ARGV[1]) " +
"local now = tonumber(redis.call('incr', key)) " +
"if now == 1 then " +
" redis.call('expire', key, ARGV[2]) " +
"end " +
"<= limit";
public boolean tryAcquire(String key, int limitCount, int limitTime) {
DefaultRedisScript<Boolean> script = new Default<>();
script.setScriptText(LIMIT_SCRIPT);
script.setResultType(Boolean.class<String> keys = Collections.singletonList(key);
// Lua参数:最大次数、过期时间
Boolean result = redisTemplate.execute(script, keys, limitCount, limitTime);
return Boolean.TRUE.equals(result);
}
}
使用 Lua 脚本保证原子性,杜绝并发限流穿透问题,生产标准写法。
4.3 新增限流 AOP 切面
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class RateLimitAspect {
@Resource
private RateLimitUtil rateLimitUtil;
@Around("@annotation(rateLimit)")
public Object around(ProceedingJoinPoint point, RateLimit rateLimit) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
// 拼接Key:IP+接口路径,精准限流
String ip = getIp(request);
String uri = request.getRequestURI();
String limitKey = rateLimit.prefix() + ip + ":" + uri;
// 校验限流
boolean acquire = rateLimitUtil.tryAcquire(limitKey, rateLimit.count(), rateLimit.time());
if (!acquire) {
return Result.fail(rateLimit.msg());
}
return point.proceed();
}
/**
* 获取真实IP
*/
private String getIp(HttpServletRequest request) {
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && xForwardedFor.length() > 0) {
return xForwardedFor.split(",")[0].trim();
}
return request.getRemoteAddr();
}
}
五、组合使用:限流 + 幂等双防护
5.1 接口直接双注解加持(企业级终极写法)
@PostMapping("/submit/order")
@RateLimit(time = 1, count = 5, msg = "操作过于频繁,每秒最多5次")
@Idempotent(message = "订单提交中,请勿重复提交")<String> submitOrder() {
// 下单业务
return Result.success("订单创建成功");
}
执行顺序
- 先限流拦截:防止刷接口、高频攻击
- 后幂等拦截:防止重复提交、重试问题
双层防护,固若金汤
六、进阶策略(生产优化)
6.1 差异化限流
- 普通接口:1 秒 10 次
- 下单 / 支付:1 秒 3~5 次
- 秒杀接口:1 秒 1 次
6.2 支持全局限流 + 用户级限流扩展
可改造 key 规则:
- 未登录:IP 限流
- 已登录:UserId + 接口限流
精准限制单个用户薅接口
6.3 解决幂等误拦截
部分业务异常需要允许重试
可扩展注解参数:autoClean = true
业务异常自动删除 Token,支持用户正常重试。
6.4 黑名单联动(高阶)
限流频繁的 IP 自动加入短时黑名单,防护恶意攻击。
七、常见面试 & 生产问题
Q1:为什么限流必须用 Lua?
Redis 多条命令非原子,高并发下会超限流,Lua 脚本保证一次性执行,绝对原子安全。
Q2:限流和幂等顺序能不能反过来?
绝对不能!
如果先幂等、后限流:恶意流量依然会打满 AOP、占用线程,失去系统保护意义。
Q3:集群环境是否兼容?
完全兼容,基于 Redis 全局计数,分布式统一限流、统一防重。
八、终极总结(企业级架构)
- 幂等保证数据安全,解决业务重复问题
- 限流保证系统安全,解决流量打爆问题
- 生产写接口必须双注解同时开启
- 一套 AOP 注解框架,零侵入、开箱即用、适配所有项目
欢迎点赞、收藏、关注!持续更新 SpringBoot、微服务、分布式实战干货,带你吃透生产级技术!
更多推荐


所有评论(0)