在开发 Web 应用时,接口防刷(防止恶意或高频请求)是一个常见的需求。以下是五种常见的实现方案,适用于 Spring Boot 项目:
![图片[1]_Spring Boot 实现接口防刷的五种方案_知途无界](https://zhituwujie.com/wp-content/uploads/2025/04/d2b5ca33bd20250410093946.png)
方案一:基于 IP 的请求限制
原理
通过记录客户端的 IP 地址,对同一 IP 的请求频率进行限制。
实现方式
- 使用
Guava的RateLimiter或 Redis 计数器。 - 记录每个 IP 的请求次数,设置时间窗口(如 1 分钟内最多允许 100 次请求)。
- 如果超过限制,返回错误响应(如 HTTP 429 Too Many Requests)。
代码示例
@RestController
public class RateLimitController {
private final Map<String, Long> ipRequestMap = new ConcurrentHashMap<>();
private static final int MAX_REQUESTS = 100;
private static final long TIME_WINDOW = 60 * 1000; // 1分钟
@GetMapping("/api/test")
public ResponseEntity<String> testEndpoint(@RequestHeader("X-Forwarded-For") String ip) {
long currentTime = System.currentTimeMillis();
ipRequestMap.putIfAbsent(ip, currentTime);
Long firstRequestTime = ipRequestMap.get(ip);
if (currentTime - firstRequestTime > TIME_WINDOW) {
// 重置时间窗口
ipRequestMap.put(ip, currentTime);
} else if (ipRequestMap.values().stream().filter(time -> time >= firstRequestTime).count() > MAX_REQUESTS) {
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("请求过于频繁");
}
return ResponseEntity.ok("请求成功");
}
}
优化建议
- 使用 Redis 实现分布式请求计数。
- 配合 Nginx 或网关层进行 IP 限制。
方案二:基于 Token 的限流
原理
为每个用户生成唯一的 Token,Token 附带时间戳和请求次数,服务器验证 Token 的有效性。
实现方式
- 用户登录后生成 Token,Token 中包含用户 ID 和请求计数。
- 每次请求时验证 Token,并更新计数。
- 如果计数超过限制,拒绝请求。
代码示例
@RestController
public class TokenLimitController {
private final Map<String, Integer> tokenMap = new ConcurrentHashMap<>();
@PostMapping("/login")
public String login() {
// 模拟生成 Token
String token = UUID.randomUUID().toString();
tokenMap.put(token, 0);
return token;
}
@GetMapping("/api/test")
public ResponseEntity<String> testEndpoint(@RequestHeader("Authorization") String token) {
if (!tokenMap.containsKey(token)) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("无效的 Token");
}
int count = tokenMap.compute(token, (k, v) -> v == null ? 0 : v + 1);
if (count > 10) { // 每 Token 限制 10 次请求
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("请求过于频繁");
}
return ResponseEntity.ok("请求成功");
}
}
优化建议
- 使用 JWT 或 Redis 存储 Token。
- 配合前端实现 Token 的自动刷新。
方案三:基于滑动窗口算法的限流
原理
滑动窗口算法通过记录每个请求的时间戳,动态计算时间窗口内的请求次数。
实现方式
- 使用
LinkedHashMap或 Redis 的Sorted Set存储请求时间戳。 - 每次请求时移除窗口外的旧时间戳,计算剩余时间戳的数量。
- 如果数量超过限制,拒绝请求。
代码示例
@RestController
public class SlidingWindowController {
private final Map<String, LinkedList<Long>> ipRequestMap = new ConcurrentHashMap<>();
private static final int MAX_REQUESTS = 100;
private static final long TIME_WINDOW = 60 * 1000; // 1分钟
@GetMapping("/api/test")
public ResponseEntity<String> testEndpoint(@RequestHeader("X-Forwarded-For") String ip) {
long currentTime = System.currentTimeMillis();
ipRequestMap.computeIfAbsent(ip, k -> new LinkedList<>()).add(currentTime);
LinkedList<Long> requests = ipRequestMap.get(ip);
while (!requests.isEmpty() && requests.peekFirst() < currentTime - TIME_WINDOW) {
requests.pollFirst();
}
if (requests.size() > MAX_REQUESTS) {
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("请求过于频繁");
}
return ResponseEntity.ok("请求成功");
}
}
优化建议
- 使用 Redis 的
ZADD和ZREMRANGEBYSCORE实现分布式滑动窗口。
方案四:使用网关层限流
原理
在 API 网关(如 Nginx、Spring Cloud Gateway、Kong)中配置限流规则,拦截恶意请求。
实现方式
- 配置 Nginx 的
limit_req模块。 - 使用 Spring Cloud Gateway 的
RequestRateLimiter过滤器。
Nginx 示例
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
server {
location /api/ {
limit_req zone=one burst=20 nodelay;
}
}
}
Spring Cloud Gateway 示例
spring:
cloud:
gateway:
routes:
- id: rate_limiter_route
uri: http://example.org
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
predicates:
- Path=/api/**
方案五:验证码机制
原理
对于高风险接口(如登录、支付),要求用户输入验证码,防止自动化脚本刷接口。
实现方式
- 集成第三方验证码服务(如阿里云、腾讯云)。
- 在关键接口前增加验证码验证逻辑。
代码示例
@RestController
public class CaptchaController {
@GetMapping("/api/captcha")
public String generateCaptcha() {
// 生成验证码并返回给前端
return "模拟验证码";
}
@PostMapping("/api/sensitive")
public ResponseEntity<String> sensitiveOperation(@RequestParam String captcha) {
if (!"1234".equals(captcha)) { // 模拟验证码验证
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("验证码错误");
}
return ResponseEntity.ok("操作成功");
}
}
总结与选择
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 基于 IP 的请求限制 | 简单接口防刷 | 实现简单,无需用户登录 | 无法区分正常用户和恶意用户 |
| 基于 Token 的限流 | 用户登录后的接口 | 精准限流,用户体验较好 | 需要用户登录,复杂度较高 |
| 滑动窗口算法 | 高并发场景 | 限流精准,资源占用少 | 实现复杂 |
| 网关层限流 | 分布式系统 | 性能高,集中管理 | 需要额外部署网关 |
| 验证码机制 | 高风险接口 | 防止自动化脚本刷接口 | 用户体验较差 |
推荐:
- 对于简单接口,优先使用 基于 IP 的请求限制。
- 对于用户登录后的接口,使用 基于 Token 的限流。
- 对于高并发场景,结合 滑动窗口算法 和 网关层限流。
- 对于高风险接口,增加 验证码机制。
通过组合多种方案,可以更有效地防止接口被恶意刷取。
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END

























暂无评论内容