在现代互联网应用中,为了保护系统的稳定和数据的安全,常常需要对API接口进行限流和防刷。本文将介绍几种在Spring Boot应用中实现API限流与防刷的方式,帮助开发人员保护接口免受滥用和恶意攻击。
1. 基于注解的限流
Spring Boot提供了自定义注解的能力,可以通过自定义注解来标注需要进行限流的接口方法。通过AOP技术,在方法执行之前判断是否需要限流,并采取相应的措施。
首先,在Spring Boot项目的pom.xml文件中添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
然后,创建一个自定义注解@RateLimit
:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
int value() default 1;
int seconds() default 60;
String key() default "default";
}
接下来,在Spring Boot的配置文件中添加限流的相关配置:
rate-limit:
enable: true
limit: 10
interval: 60
然后,在项目的AOP切面中实现限流逻辑:
@Aspect
@Component
public class RateLimitAspect {
@Autowired
private HttpServletRequest request;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Around("@annotation(com.example.demo.annotation.RateLimit)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
RateLimit rateLimit = method.getAnnotation(RateLimit.class);
HttpServletRequest httpRequest = (HttpServletRequest) joinPoint.getArgs()[0];
String ip = getIpAddress(httpRequest);
String key = rateLimit.key() + "-" + ip;
boolean allowed = isAllowed(key, rateLimit.limit(), rateLimit.interval());
if (allowed) {
return joinPoint.proceed();
} else {
return new ApiResponse(429, "Too Many Requests");
}
}
private boolean isAllowed(String key, int limit, int interval) {
Long count = redisTemplate.opsForValue().increment(key, 1);
if (count == 1) {
redisTemplate.expire(key, interval, TimeUnit.SECONDS);
}
return count <= limit;
}
private String getIpAddress(HttpServletRequest request) {
// 省略获取IP地址的逻辑
}
}
最后,在需要进行限流的接口方法上加上@RateLimit
注解即可:
@RestController
public class ApiController {
@RateLimit(limit = 10, seconds = 60, key = "api")
@GetMapping("/api/hello")
public ApiResponse sayHello(HttpServletRequest request) {
return new ApiResponse(200, "Hello");
}
}
2. 使用Redis实现计数器
另一种常用的限流方式是使用Redis作为计数器。每当有请求到来时,通过自增操作更新计数器的值,并设置过期时间。如果计数器达到限制值,就拒绝请求。
首先,在Spring Boot项目的pom.xml文件中添加Redis的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
然后,配置Redis连接信息:
spring:
redis:
host: localhost
port: 6379
password:
database: 0
接下来,通过使用RedisTemplate来进行操作Redis:
@Component
public class RateLimiter {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public boolean isAllowed(String key, int limit, int interval) {
String redisKey = "ratelimiter:" + key;
Long count = redisTemplate.opsForValue().increment(redisKey, 1);
if (count == 1) {
redisTemplate.expire(redisKey, interval, TimeUnit.SECONDS);
}
return count <= limit;
}
}
最后,在需要进行限流的地方使用RateLimiter来进行限流判断:
@RestController
public class ApiController {
@Autowired
private RateLimiter rateLimiter;
@GetMapping("/api/hello")
public ApiResponse sayHello(HttpServletRequest request) {
if (rateLimiter.isAllowed("api", 10, 60)) {
return new ApiResponse(200, "Hello");
} else {
return new ApiResponse(429, "Too Many Requests");
}
}
}
3. 使用第三方限流组件
除了上述两种方式外,还可以使用第三方限流组件来实现API的限流与防刷。比如常用的限流组件有Guava RateLimiter、Netflix的Hystrix、Sentinel等。
选择适合项目需求的限流组件,按照组件提供的文档和示例进行配置和使用即可。
总结
本文介绍了在Spring Boot应用中实现API限流与防刷的几种方式,包括基于注解的限流、使用Redis实现计数器和使用第三方限流组件。根据项目需求和实际情况选择合适的方式,可以有效保护API接口免受滥用和恶意攻击,提高系统的稳定性和安全性。
本文来自极简博客,作者:算法架构师,转载请注明原文链接:Spring Boot应用中实现API限流与防刷的几种方式