主要变更: 1. 所有 Entity/DTO/VO 添加 @Schema 注解,完善 API 文档 2. 新增前端 API 封装模块 (src/apis),包含 fetch.ts 和 apis.ts 3. 生成完整的 TypeScript 类型定义(100+ 个模型) 4. pom.xml 添加 Maven 编译配置和 UTF-8 编码支持 5. 更新 CLAUDE.md 开发文档,新增接口规范和 Swagger 注解规范 6. 清理旧的文档文件和 Flyway 迁移脚本 技术细节: - 后端:27 个实体类 + 所有 DTO/Response 添加 Swagger 注解 - 前端:新增 orval 生成的 API 客户端类型 - 构建:配置 Maven compiler plugin 和 Spring Boot 插件的 JVM 参数 - 数据库:新增 schema 导出文件,删除旧 Flyway 迁移脚本 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
225 lines
6.4 KiB
Markdown
225 lines
6.4 KiB
Markdown
# 限流功能使用说明
|
||
|
||
## 功能概述
|
||
|
||
本项目已集成基于 Redis 滑动窗口算法的限流功能,支持两种使用方式:
|
||
1. **配置化限流** - 在 `application.yml` 中配置规则,自动对所有接口生效
|
||
2. **注解限流** - 在 Controller 方法上使用 `@RateLimit` 注解,针对特定接口限流
|
||
|
||
## 技术实现
|
||
|
||
### 核心组件
|
||
|
||
| 组件 | 说明 |
|
||
|------|------|
|
||
| `@RateLimit` | 限流注解,可自定义时间窗口、最大请求数 |
|
||
| `RateLimitProperties` | 配置化限流的属性类 |
|
||
| `RateLimiter` | Redis 限流工具类(滑动窗口算法) |
|
||
| `RateLimitAspect` | 注解限流的 AOP 切面 |
|
||
| `RateLimitInterceptor` | 配置化限流的拦截器 |
|
||
| `ErrorCode.RATE_LIMIT_EXCEEDED` | 限流错误码(5001) |
|
||
|
||
### 限流优先级
|
||
|
||
**注解限流 > 配置化限流 > 默认限流**
|
||
|
||
## 使用方式
|
||
|
||
### 方式一:配置化限流(推荐作为基础防护)
|
||
|
||
在 `application.yml` 中配置:
|
||
|
||
```yaml
|
||
rate-limit:
|
||
enabled: true # 是否启用限流
|
||
default-time-window: 60 # 默认时间窗口(秒)
|
||
default-max-requests: 1000 # 默认时间窗口内最大请求数
|
||
rules: # 限流规则列表
|
||
# 登录接口限流 - 防止暴力破解
|
||
- pattern: "/api/v1/auth/login"
|
||
time-window: 60
|
||
max-requests: 10
|
||
# 验证码接口限流 - 防止刷验证码
|
||
- pattern: "/api/v1/auth/captcha"
|
||
time-window: 60
|
||
max-requests: 5
|
||
# 短信接口限流 - 防止短信轰炸
|
||
- pattern: "/api/v1/sms/**"
|
||
time-window: 60
|
||
max-requests: 3
|
||
# 文件上传接口限流
|
||
- pattern: "/api/v1/**/upload/**"
|
||
time-window: 60
|
||
max-requests: 30
|
||
exclude-patterns: # 排除限流的接口
|
||
- "/doc.html"
|
||
- "/swagger-resources/**"
|
||
- "/v3/api-docs/**"
|
||
- "/webjars/**"
|
||
- "/uploads/**"
|
||
```
|
||
|
||
### 方式二:注解限流(针对特殊接口)
|
||
|
||
在 Controller 方法上添加 `@RateLimit` 注解:
|
||
|
||
```java
|
||
package com.reading.platform.controller.auth;
|
||
|
||
import com.reading.platform.common.annotation.RateLimit;
|
||
import com.reading.platform.common.response.Result;
|
||
import org.springframework.web.bind.annotation.*;
|
||
|
||
@RestController
|
||
@RequestMapping("/api/v1/auth")
|
||
public class AuthController {
|
||
|
||
/**
|
||
* 登录接口 - 限流防止暴力破解
|
||
* 60 秒内最多 10 次请求
|
||
*/
|
||
@PostMapping("/login")
|
||
@RateLimit(time = 60, maxRequests = 10, message = "登录过于频繁,请稍后再试")
|
||
public Result<LoginResponse> login(@RequestBody LoginRequest request) {
|
||
// ... 登录逻辑
|
||
}
|
||
|
||
/**
|
||
* 发送短信验证码 - 严格限流
|
||
* 60 秒内最多 3 次请求
|
||
*/
|
||
@PostMapping("/captcha")
|
||
@RateLimit(time = 60, maxRequests = 3, message = "操作过于频繁,请稍后再试")
|
||
public Result<Void> sendCaptcha(@RequestParam String phone) {
|
||
// ... 发送验证码逻辑
|
||
}
|
||
|
||
/**
|
||
* 自定义限流键前缀
|
||
* 适用于需要按用户 ID 等特殊维度限流的场景
|
||
*/
|
||
@PostMapping("/special")
|
||
@RateLimit(keyPrefix = "special_api:", time = 60, maxRequests = 5)
|
||
public Result<Void> specialApi() {
|
||
// ... 特殊接口逻辑
|
||
}
|
||
}
|
||
```
|
||
|
||
## 常见限流场景建议值
|
||
|
||
| 接口类型 | 时间窗口 | 最大请求数 | 说明 |
|
||
|---------|---------|-----------|------|
|
||
| 登录接口 | 60 秒 | 10 | 防止暴力破解 |
|
||
| 验证码/短信 | 60 秒 | 3-5 | 防止短信轰炸 |
|
||
| 文件上传 | 60 秒 | 30 | 防止资源滥用 |
|
||
| 普通业务接口 | 60 秒 | 100-1000 | 根据业务调整 |
|
||
| 导出接口 | 60 秒 | 5-10 | 防止服务器过载 |
|
||
|
||
## 限流响应
|
||
|
||
当请求被限流拦截时,返回:
|
||
|
||
**配置化限流响应:**
|
||
```json
|
||
{
|
||
"code": 5001,
|
||
"message": "请求过于频繁,请稍后再试",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
HTTP 状态码:`429 Too Many Requests`
|
||
|
||
响应头:
|
||
```
|
||
X-RateLimit-Limit: 1
|
||
X-RateLimit-Remaining: 0
|
||
Retry-After: 60
|
||
```
|
||
|
||
**注解限流响应:**
|
||
```json
|
||
{
|
||
"code": 5001,
|
||
"message": "登录过于频繁,请稍后再试",
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
## Redis 数据结构
|
||
|
||
限流使用 Redis 的 `Sorted Set`(有序集合)存储:
|
||
|
||
- **Key 格式**: `rate_limit:{key}`
|
||
- **Member**: 时间戳(毫秒)
|
||
- **Score**: 时间戳(毫秒)
|
||
|
||
示例:
|
||
```
|
||
rate_limit:192.168.1.1:/api/v1/auth/login
|
||
|- 1710000000000
|
||
|- 1710000001000
|
||
|- 1710000002000
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
1. **Redis 依赖**: 限流功能依赖 Redis,需确保 Redis 服务可用
|
||
2. **异常情况放行**: 当 Redis 不可用时,系统会自动放行请求,避免影响正常业务
|
||
3. **集群部署**: 滑动窗口算法天然支持分布式,无需额外配置
|
||
4. **监控告警**: 建议添加限流触发的监控告警,及时发现异常流量
|
||
|
||
## 日志示例
|
||
|
||
```
|
||
2024-03-10 22:00:00 WARN - 请求被限流拦截:URI=/api/v1/auth/login, 规则=/api/v1/auth/login, 最大请求数=10
|
||
2024-03-10 22:00:01 DEBUG - 请求通过限流检查:URI=/api/v1/users, 规则=default
|
||
```
|
||
|
||
## 测试方法
|
||
|
||
使用 `curl` 或 Postman 快速测试:
|
||
|
||
```bash
|
||
# 循环发送 15 次登录请求(第 11 次开始应该被限流)
|
||
for i in {1..15}; do
|
||
echo "请求 $i:"
|
||
curl -X POST http://localhost:8080/api/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"username":"test","password":"test"}' \
|
||
-w "\nHTTP 状态码:%{http_code}\n\n"
|
||
done
|
||
```
|
||
|
||
## 配置说明
|
||
|
||
### RateLimit 注解参数
|
||
|
||
| 参数 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `keyPrefix` | String | "" | 限流键前缀,默认使用 `IP:类名。方法名` |
|
||
| `time` | long | 60 | 时间窗口大小 |
|
||
| `timeUnit` | TimeUnit | SECONDS | 时间单位 |
|
||
| `maxRequests` | long | 100 | 时间窗口内最大请求数 |
|
||
| `message` | String | "请求过于频繁,请稍后再试" | 限流提示信息 |
|
||
| `enabled` | boolean | true | 是否启用限流 |
|
||
|
||
### application.yml 配置参数
|
||
|
||
| 参数 | 类型 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `enabled` | boolean | true | 是否启用限流 |
|
||
| `default-time-window` | long | 60 | 默认时间窗口(秒) |
|
||
| `default-max-requests` | long | 1000 | 默认最大请求数 |
|
||
| `rules` | List | [] | 限流规则列表 |
|
||
| `exclude-patterns` | List | [] | 排除限流的接口路径 |
|
||
|
||
### RateLimitRule 配置参数
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `pattern` | String | 接口路径(支持 Ant 风格通配符) |
|
||
| `time-window` | long | 时间窗口(秒) |
|
||
| `max-requests` | long | 最大请求数 |
|