# 限流功能使用说明

## 功能概述

本项目已集成基于 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 | 最大请求数 |
