You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iTi-Flask-IOT/docs/LIMITER_CONFIG.md

306 lines
6.2 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 限流器配置说明
## 📋 概述
项目使用 Flask-Limiter 实现 API 限流功能,支持基于 Flask 配置的动态设置。
## 🔧 配置项
### 基础配置
| 配置项 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| `RATELIMIT_ENABLED` | bool | `True` | 是否启用限流 |
| `RATELIMIT_STORAGE_URL` | str | `"memory://"` | 存储后端 URI |
| `RATELIMIT_DEFAULT` | str | `"200 per hour"` | 默认限流规则 |
### 环境配置
#### 开发环境 (DevConfig)
```python
RATELIMIT_ENABLED = True
RATELIMIT_STORAGE_URL = "memory://"
RATELIMIT_DEFAULT = "1000 per hour" # 宽松限制
```
#### 测试环境 (TestConfig)
```python
RATELIMIT_ENABLED = False # 禁用限流
```
#### 生产环境 (ProdConfig)
```python
RATELIMIT_ENABLED = True
RATELIMIT_STORAGE_URL = os.getenv("REDIS_URL", "memory://")
RATELIMIT_DEFAULT = "100 per hour" # 严格限制
```
## 🚀 使用方式
### 1. 基本使用
```python
from flask import Flask, jsonify
from iti.applications.extensions.limit import limiter
app = Flask(__name__)
@app.route('/api/data')
@limiter.limit("10 per minute") # 每分钟10次
def get_data():
return jsonify({'data': 'some data'})
```
### 2. 使用默认限流
```python
@app.route('/api/public')
def public_api():
# 使用配置中的默认限流规则
return jsonify({'message': 'Public API'})
```
### 3. 豁免限流
```python
@app.route('/api/health')
@limiter.exempt # 豁免限流
def health_check():
return jsonify({'status': 'healthy'})
```
### 4. 自定义键函数
```python
@app.route('/api/user-data')
@limiter.limit("50 per hour", key_func=lambda: "user_123")
def user_data():
return jsonify({'user': 'user_123', 'data': 'user data'})
```
## 🔧 配置示例
### 使用 .env 文件
```env
# .env
RATELIMIT_ENABLED=true
RATELIMIT_STORAGE_URL=memory://
RATELIMIT_DEFAULT=200 per hour
# .env.prod
RATELIMIT_ENABLED=true
RATELIMIT_STORAGE_URL=redis://localhost:6379/0
RATELIMIT_DEFAULT=100 per hour
```
### 使用环境变量
```bash
# Windows
set RATELIMIT_ENABLED=true
set RATELIMIT_STORAGE_URL=redis://localhost:6379/0
set RATELIMIT_DEFAULT=100 per hour
# Linux/macOS
export RATELIMIT_ENABLED=true
export RATELIMIT_STORAGE_URL=redis://localhost:6379/0
export RATELIMIT_DEFAULT=100 per hour
```
## 📊 存储后端
### 内存存储 (开发环境)
```python
RATELIMIT_STORAGE_URL = "memory://"
```
- ✅ 简单快速
- ❌ 重启后数据丢失
- ❌ 不支持多进程
### Redis 存储 (生产环境)
```python
RATELIMIT_STORAGE_URL = "redis://localhost:6379/0"
```
- ✅ 持久化存储
- ✅ 支持多进程
- ✅ 高性能
- ⚠️ 需要 Redis 服务
### 其他存储选项
```python
# Memcached
RATELIMIT_STORAGE_URL = "memcached://localhost:11211"
# 文件存储
RATELIMIT_STORAGE_URL = "file:///tmp/limiter.db"
```
## 🎯 限流规则语法
### 时间单位
- `second` / `sec` - 秒
- `minute` / `min` - 分钟
- `hour` - 小时
- `day` - 天
- `month` - 月
- `year` - 年
### 示例规则
```python
"10 per second" # 每秒10次
"100 per minute" # 每分钟100次
"1000 per hour" # 每小时1000次
"10000 per day" # 每天10000次
```
### 复杂规则
```python
"10 per minute; 100 per hour" # 每分钟10次每小时100次
"5 per minute; 50 per hour; 500 per day" # 多级限流
```
## 🔍 调试和监控
### 检查限流状态
```python
@app.route('/api/limiter-status')
def limiter_status():
if limiter is None:
return jsonify({'enabled': False})
return jsonify({
'enabled': True,
'default_limits': limiter.default_limits,
'storage_uri': limiter.storage_uri,
'key_func': limiter.key_func.__name__
})
```
### 查看限流信息
```python
from flask_limiter.util import get_remote_address
# 获取当前用户的限流信息
limits = limiter.get_window_stats(get_remote_address())
print(f"剩余请求: {limits[1] - limits[0]}")
```
## 🛠️ 故障排查
### 问题 1: 限流不生效
**检查步骤:**
1. 确认 `RATELIMIT_ENABLED=True`
2. 检查存储后端是否可用
3. 验证限流规则语法
**调试方法:**
```python
print(f"限流启用: {app.config.get('RATELIMIT_ENABLED')}")
print(f"存储URI: {app.config.get('RATELIMIT_STORAGE_URL')}")
print(f"默认限制: {app.config.get('RATELIMIT_DEFAULT')}")
```
### 问题 2: Redis 连接失败
**检查步骤:**
1. 确认 Redis 服务运行
2. 检查连接字符串格式
3. 验证网络连接
**解决方案:**
```python
# 使用内存存储作为后备
RATELIMIT_STORAGE_URL = os.getenv("REDIS_URL", "memory://")
```
### 问题 3: 限流过于严格
**调整方法:**
```python
# 在配置中调整
RATELIMIT_DEFAULT = "1000 per hour" # 更宽松的限制
# 或在路由中覆盖
@limiter.limit("500 per hour")
def my_endpoint():
pass
```
## 📚 最佳实践
### 1. 环境配置
```python
# 开发环境 - 宽松限制
RATELIMIT_DEFAULT = "1000 per hour"
# 测试环境 - 禁用限流
RATELIMIT_ENABLED = False
# 生产环境 - 严格限制
RATELIMIT_DEFAULT = "100 per hour"
RATELIMIT_STORAGE_URL = "redis://localhost:6379/0"
```
### 2. 路由设计
```python
# 公共 API - 宽松限制
@app.route('/api/public')
@limiter.limit("100 per hour")
def public_api():
pass
# 私有 API - 严格限制
@app.route('/api/private')
@limiter.limit("10 per hour")
def private_api():
pass
# 健康检查 - 豁免限流
@app.route('/health')
@limiter.exempt
def health():
pass
```
### 3. 错误处理
```python
from flask_limiter.errors import RateLimitExceeded
@app.errorhandler(RateLimitExceeded)
def handle_rate_limit_exceeded(e):
return jsonify({
'error': 'Rate limit exceeded',
'message': 'Too many requests',
'retry_after': e.retry_after
}), 429
```
## 🎉 总结
现在您的项目:
1.**支持基于配置的限流** - 从 Flask 配置中读取设置
2.**环境特定配置** - 不同环境使用不同的限流策略
3.**灵活的存储后端** - 支持内存、Redis 等
4.**易于调试** - 提供状态检查和错误处理
5.**生产就绪** - 支持高并发和持久化存储
**开始使用:**
```python
from iti.applications.extensions.limit import limiter
@app.route('/api/data')
@limiter.limit("10 per minute")
def get_data():
return jsonify({'data': 'some data'})
```
就这么简单!🚀