File size: 1,248 Bytes
8f823b0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import time
from collections import defaultdict
from fastapi import Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
class RateLimitMiddleware(BaseHTTPMiddleware):
"""API限流中间件"""
def __init__(self, app, calls_per_minute: int = 60):
super().__init__(app)
self.calls_per_minute = calls_per_minute
self.calls = defaultdict(list)
async def dispatch(self, request: Request, call_next):
client_ip = request.client.host if request.client else "unknown"
current_time = time.time()
# 清理过期的调用记录
minute_ago = current_time - 60
self.calls[client_ip] = [
call_time for call_time in self.calls[client_ip]
if call_time > minute_ago
]
# 检查是否超过限制
if len(self.calls[client_ip]) >= self.calls_per_minute:
raise HTTPException(
status_code=429,
detail=f"请求频率过高,每分钟最多允许 {self.calls_per_minute} 次请求"
)
# 记录本次调用
self.calls[client_ip].append(current_time)
# 处理请求
response = await call_next(request)
return response
|