spring boot统一接口限流推荐redis+拦截器+计数器方案,基于请求路径与ip生成key,用lua脚本原子执行incr/expire/判断,支持yml动态配置多规则,并辅以nginx限流、验证码、ip黑名单及告警。

在 Spring Boot 中配置统一接口限流,核心目标是:不侵入业务代码、支持分布式环境、规则可配、响应规范。推荐采用「Redis + 拦截器 + 计数器」组合方案,兼顾简洁性与生产可用性。
用拦截器统一拦截请求
定义一个全局拦截器,在请求进入 Controller 前做限流校验。它能覆盖所有 HTTP 接口(含 GET/POST 等),无需每个方法加注解。
- 拦截器根据 请求路径 + 客户端 IP 组合成唯一 key,例如:
rate:limit:/api/order:192.168.1.100 - 使用
StringRedisTemplate对该 key 执行INCR并设置过期时间(如 60 秒),实现滑动窗口计数 - 若返回值 > 阈值(如 100 次/分钟),直接返回
429 Too Many Requests和统一 JSON 提示
按需配置不同接口的限流阈值
硬编码阈值不灵活。建议将限流规则外置,例如放在 application.yml 中:
rate-limit:
rules:
- path: /api/login
ip-based: true
max-requests: 5
window-seconds: 60
- path: /api/sms/send
ip-based: true
max-requests: 1
window-seconds: 300
- path: /api/public/weather
ip-based: false # 全局共享,不限 IP
max-requests: 1000
window-seconds: 3600
启动时加载这些规则,拦截器运行时动态匹配路径并应用对应策略。
避免 Redis 单点与并发问题
直接用 INCR + EXPIRE 两步操作存在竞态风险(如 SETNX 失败后 EXPIRE 不生效)。更稳妥的做法是:
- 用 Lua 脚本原子执行「自增 + 判断 + 设置过期」,确保计数准确
- 脚本示例(RedisTemplate 可直接执行):
local key = KEYS[1]<br>local limit = tonumber(ARGV[1])<br>local window = tonumber(ARGV[2])<br>local current = redis.call("INCR", key)<br>if current == 1 then<br> redis.call("EXPIRE", key, window)<br>end<br>if current > limit then<br> return 0<br>else<br> return 1<br>end - 返回 0 表示被限流,1 表示放行
补充防护增强鲁棒性
单一限流不够?加几层“保险”:
-
前置 Nginx 限流:作为第一道防线,用
limit_req控制 IP 级别 QPS,减轻应用层压力 - 关键接口加验证码:登录、注册、短信发送等高风险接口,强制首次请求携带图形或滑块验证码
- 异常 IP 自动拉黑:连续触发限流达阈值(如 5 分钟内被限 10 次),写入黑名单缓存(如 Redis Set),后续请求直接拒绝
- 日志与告警联动:记录被限流的 IP、路径、时间,接入 ELK 或 Prometheus+AlertManager,流量突增时自动通知
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











