Гайды
CORS, middleware и лимиты запросов в FastAPI
CORSMiddleware, request id, TrustedHost, slowapi, gzip, security headers и чек-лист для prod.
~9 мин чтения
CORS, middleware и лимиты запросов в FastAPI
CORS настраивается middleware Starlette; лимиты — через собственный middleware или библиотеку (slowapi на базе limits). Аутентификация — JWT и OAuth2; деплой за Nginx — Docker и Nginx.
1. CORS
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["https://app.example.com"], # не "*" с credentials
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
allow_headers=["*"],
expose_headers=["X-Request-Id"],
max_age=600,
)
allow_origins=["*"] несовместимо с allow_credentials=True по спецификации браузера.
Для публичного API без cookies иногда допустим * без credentials.
2. Свой middleware: логирование и request id
import uuid
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
class RequestIdMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
rid = request.headers.get("X-Request-Id", str(uuid.uuid4()))
request.state.request_id = rid
response = await call_next(request)
response.headers["X-Request-Id"] = rid
return response
app.add_middleware(RequestIdMiddleware)
Порядок: последний добавленный выполняется первым на входе (onion model).
3. TrustedHost
from fastapi.middleware.trustedhost import TrustedHostMiddleware
app.add_middleware(TrustedHostMiddleware, allowed_hosts=["api.example.com", "*.example.com"])
За балансировщиком учитывайте proxy_headers в uvicorn — см. деплой.
4. Лимиты запросов (slowapi)
pip install slowapi
from starlette.requests import Request
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
@app.get("/search")
@limiter.limit("30/minute")
def search(request: Request, q: str):
return {"q": q}
Для пользовательских лимитов key_func может брать user_id из JWT (осторожно с кэшированием Depends).
За reverse proxy get_remote_address увидит IP балансировщика. В uvicorn включайте --proxy-headers и --forwarded-allow-ips для доверенных сетей; в key_func разбирайте X-Forwarded-For (первый клиентский IP слева с учётом доверенных hop'ов), иначе лимит «на весь мир» схлопнется в один IP.
Для распределённого подсчёта в нескольких воркерах uvicorn храните счётчики в Redis (limits + storage) — in-memory slowapi не синхронизируется между процессами.
5. Таймауты тела
Ограничение размера тела задаётся на уровне ASGI-сервера (uvicorn) или reverse proxy (Nginx client_max_body_size).
6. GZip
from starlette.middleware.gzip import GZipMiddleware
app.add_middleware(GZipMiddleware, minimum_size=1000)
7. Security headers (частично в Nginx)
X-Content-Type-Options, X-Frame-Options, CSP — часто на границе CDN/Nginx, не дублируйте конфликтующе.
8. Чек-лист
- Явный список
allow_originsдля prod. - Rate limit на
/tokenи публичные поиски. - Request id в логах и ответе.
- TrustedHost за известным прокси.
Дальше: Быстрый старт · тег FastAPI