spring mvc 中用拦截器实现 api 访问频率限制,核心是在请求到达 controller 前基于 redis 对 ip+接口路径计数并设置过期时间,超阈值返回 429;支持注解灵活配置、防 ip 伪造、并发安全及正确中断流程。

Spring MVC 中用拦截器实现 API 访问频率限制,核心是在请求到达 Controller 前做判断:同一 IP(或用户标识)在指定时间窗口内是否超出了允许的调用次数。关键在于“计数 + 过期控制 + 快速响应”,而不是简单累加后清零。
用 Redis 实现分布式限流(推荐)
单机内存方案(如 ConcurrentHashMap)在集群环境下失效,生产环境应优先使用 Redis 存储访问记录,保证多实例间状态一致。
- 以 IP + 接口路径(如
192.168.1.100:/api/send-sms)为唯一 key,避免不同接口互相干扰 - 每次请求时,用
INCR命令增加计数,并通过EXPIRE设置过期时间(如 60 秒),确保窗口自动滚动 - 若返回值 > 限流阈值(如 5 次/分钟),直接设置响应状态码
429 Too Many Requests并中断请求 - 注意:不要在每次请求都重设 EXPIRE,而应在首次写入时设置;Redis 的 INCR + EXPIRE 组合天然支持“首次创建带过期”的语义
基于注解的灵活控制
不希望全局限流?可以定义一个自定义注解,只对特定接口生效:
- 声明注解
@RateLimit(count = 5, time = 60),标注在 Controller 方法上 - 拦截器中通过
HandlerMethod反射获取该注解,提取配置参数 - 这样就能做到:短信接口限 1 次/分钟,登录接口限 10 次/小时,互不影响
- 比硬编码更易维护,也方便后续扩展(比如按用户角色动态调整阈值)
拦截器中的关键逻辑细节
别只写个 preHandle 就完事,这几个点容易出错:
-
IP 获取要防伪造:不能只用
request.getRemoteAddr(),需结合X-Forwarded-For、X-Real-IP等头字段,并校验代理链可信性 -
避免并发冲突:Redis 的 INCR 是原子操作,但如果你用本地 Map + AtomicInteger,必须加锁或改用
ConcurrentHashMap.computeIfAbsent -
拒绝请求要干净:设置
response.setStatus(429)后,务必return false,否则后续流程仍会执行 -
不记录异常请求:如果 Controller 抛了异常,
afterCompletion里不要减计数——失败调用不该占用配额
注册与生效方式
拦截器不会自动运行,需要显式注册:
- 在配置类中继承
WebMvcConfigurer,重写addInterceptors - 用
registry.addInterceptor(...).excludePathPatterns("/actuator/**", "/swagger-ui/**")排除监控和文档路径 - 可通过
@Order控制多个拦截器的执行顺序,限流拦截器建议设为最高优先级 - 测试时用
curl -I查看响应头是否含429,再用 JMeter 或 wrk 验证阈值是否准确触发
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











