Промежуточное ПО играет важную роль в веб-фреймворках, выступая в качестве слоя обработки, который находится между входящими запросами и исходящими ответами. Этот слой может изменять запросы, обрабатывать исключения, управлять сессиями, сжимать ответы и многое другое. В FastAPI промежуточное ПО расширяет функциональность приложения, делая его более надежным и многофункциональным.
Разработанный с учетом высокой гибкости, FastAPI принимает любое промежуточное ПО, соответствующее спецификации ASGI. Это означает, что вы можете интегрировать в FastAPI-приложение как встроенные промежуточные программы, предоставляемые FastAPI или Starlette, так и промежуточное ПО от сторонних производителей, а также создавать собственное промежуточное ПО для удовлетворения конкретных потребностей. Программным обеспечением ASGI может быть любой вызываемый модуль, соответствующий спецификации ASGI, что позволяет беспроблемно внедрять в FastAPI-приложение широкий спектр функциональных возможностей.
Вот перечень встроенных (FastAPI и/или Starlette) и сторонних пользовательских промежуточных программ, которые могут быть полезны при разработке приложений.
1. CORSMiddleware
Описание
CORS расшифровывается как «cross-origin resource sharing» — совместное использование ресурсов из разных источников. CORS позволяет запрашивать или ограничивать ресурсы на сервере из другого домена. Это необходимо, когда бэкенд FastAPI обслуживает клиентов различного происхождения, например фронтенд-приложения, размещенные на разных доменах.
Случаи использования
- Обеспечение безопасного использования междоменных запросов в одностраничных приложениях.
- Предоставление доступа к API из разных клиентских доменов.
Пример
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allows all origins
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def root():
return {"message": "Hello World"}
2. GZipMiddleware
Описание
Автоматически сжимает ответы с помощью алгоритма GZip, уменьшая размер полезной нагрузки и повышая производительность, особенно для больших ответов JSON или HTML.
Случаи использования
- Обслуживание больших JSON-ответов в RESTful API.
- Обслуживание статических файлов со сжатым контентом.
Пример
from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware
app = FastAPI()
app.add_middleware(GZipMiddleware, minimum_size=1000) # Сжатие ответов размером более 1000 байт
@app.get("/")
async def root():
return {"message": "This is a test message that will be compressed."}
3. HTTPSRedirectMiddleware
Описание
Позволяет автоматически перенаправить все HTTP-запросы на HTTPS, обеспечивая безопасность соединений.
Случаи использования
- Обеспечение HTTPS для веб-приложений.
- Защита конечных точек API путем обеспечения кодирования данных в сети.
Пример
from fastapi import FastAPI
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
app = FastAPI()
app.add_middleware(HTTPSRedirectMiddleware)
@app.get("/")
async def root():
return {"message": "You are being redirected to HTTPS!"}
4. SessionMiddleware
Описание
Управляет сессиями пользователей, создавая идентификатор сессии для каждого пользователя и сохраняя его в куки-файлах, что позволяет легко поддерживать взаимодействие с учетом состояния при нескольких запросах.
Случаи использования
- Управление сессиями аутентификации пользователей.
- Хранение временных данных при нескольких запросах.
Пример
from fastapi import FastAPI, Request
from starlette.middleware.sessions import SessionMiddleware
app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="your-secret-key")
@app.get("/set/")
async def set_session_data(request: Request):
request.session['user'] = 'john_doe'
return {"message": "Session data set"}
@app.get("/get/")
async def get_session_data(request: Request):
user = request.session.get('user', 'guest')
return {"user": user}
5. TrustedHostMiddleware
Описание
Фильтрует запросы, чтобы подтвердить их поступление от определенных доверенных имен хостов. Защищает от атак на заголовки хостов в HTTP-запросах.
Случаи использования
- Защита от атак на DNS-перепривязку.
- Ограничение доступа к API определенными именами хостов.
Пример
from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware
app = FastAPI()
app.add_middleware(TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com"])
@app.get("/")
async def root():
return {"message": "This request came from a trusted host."}
6. ErrorHandlingMiddleware
Описание
Это пользовательское ПО перехватывает исключения и единообразно форматирует ответы на ошибки. Его можно настроить для регистрации ошибок или уведомления служб мониторинга.
Случаи использования
- Пользовательское регистрирование ошибок.
- Единообразное форматирование ответов на ошибки во всем приложении.
Пример
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
class ErrorHandlingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
try:
response = await call_next(request)
except Exception as e:
response = JSONResponse({"error": str(e)}, status_code=500)
return response
app = FastAPI()
app.add_middleware(ErrorHandlingMiddleware)
@app.get("/")
async def root():
raise ValueError("This is an error!")
7. RateLimitingMiddleware
Описание
Ограничивает количество запросов пользователя к API за определенный промежуток времени, помогая предотвратить злоупотребления и угрозу отказа в обслуживании.
Случаи использования
- Предотвращение злонамеренного использования API путем ограничения частоты запросов.
- Реализация уровней использования для общедоступных API.
Пример
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
import time
class RateLimitMiddleware(BaseHTTPMiddleware):
def __init__(self, app, max_requests: int, window: int):
super().__init__(app)
self.max_requests = max_requests
self.window = window
self.requests = {}
async def dispatch(self, request: Request, call_next):
client_ip = request.client.host
current_time = time.time()
if client_ip not in self.requests:
self.requests[client_ip] = []
self.requests[client_ip] = [timestamp for timestamp in self.requests[client_ip] if timestamp > current_time - self.window]
if len(self.requests[client_ip]) >= self.max_requests:
return JSONResponse(status_code=429, content={"error": "Too many requests"})
self.requests[client_ip].append(current_time)
return await call_next(request)
app = FastAPI()
app.add_middleware(RateLimitMiddleware, max_requests=5, window=60)
@app.get("/")
async def root():
return {"message": "You haven't hit the rate limit yet!"}
8. AuthenticationMiddleware
Описание
Обрабатывает аутентификацию, проверяя токены или учетные данные до того, как запросы достигнут конечной точки. Его можно настроить для поддержки JWT, OAuth или других механизмов аутентификации.
Случаи использования
- Проверка API-запросов с помощью JWT-токенов.
- Реализация пользовательской логики аутентификации.
Пример
from fastapi import FastAPI, Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.responses import PlainTextResponse
class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
token = request.headers.get("Authorization")
if not token or token != "Bearer valid-token":
return PlainTextResponse(status_code=401, content="Unauthorized")
return await call_next(request)
app = FastAPI()
app.add_middleware(AuthMiddleware)
@app.get("/secure-data/")
async def secure_data():
return {"message": "This is secured data"}
9. HeadersInjectionMiddleware
Описание
Это пользовательское ПО предназначено для добавления в каждый ответ определенных заголовков, которые могут включать пользовательские токены аутентификации, идентификаторы корреляции, заголовки безопасности (security headers) и любые другие пользовательские метаданные.
Случаи использования
- Добавление пользовательских заголовков, например токенов аутентификации, метаданных, идентификаторов корреляции и т. д.
- Повышение безопасности за счет установки соответствующих HTTP-заголовков, предотвращающих распространенные веб-уязвимости.
- Контроль над поведением браузера/клиента при кэшировании путем установки заголовков для управления кэшем.
Пример
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
class CustomHeaderMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
response = await call_next(request)
response.headers['Cache-Control'] = 'public, max-age=3600'
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
return response
app = FastAPI()
app.add_middleware(CustomHeaderMiddleware)
@app.get("/data/")
async def get_data():
return {"message": "This response is cached for 1 hour."}
10. LoggingMiddleware
Описание
Обеспечивает ведение журнала, регистрируя каждый запрос и ответ, что полезно для отладки и мониторинга использования API.
Случаи использования
- Отладка проблем путем отслеживания циклов запросов/ответов.
- Мониторинг производительности API.
Пример
from fastapi import FastAPI, Request
import logging
from starlette.middleware.base import BaseHTTPMiddleware
logger = logging.getLogger("my_logger")
class LoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
logger.info(f"Request: {request.method} {request.url}")
response = await call_next(request)
logger.info(f"Response status: {response.status_code}")
return response
app = FastAPI()
app.add_middleware(LoggingMiddleware)
@app.get("/")
async def root():
return {"message": "Check your logs for the request and response details."}
11. TimeoutMiddleware
Описание
Обеспечивает прерывание запросов, если они занимают больше определенного времени, не позволяя длительным запросам истощать ресурсы сервера.
Случаи использования
- Предотвращение истощения ресурсов из-за длительных запросов.
- Обеспечение своевременных ответов в приложениях, требующих высокого трафика.
Пример
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import PlainTextResponse
import asyncio
from starlette.middleware.base import BaseHTTPMiddleware
class TimeoutMiddleware(BaseHTTPMiddleware):
def __init__(self, app, timeout: int):
super().__init__(app)
self.timeout = timeout
async def dispatch(self, request: Request, call_next):
try:
return await asyncio.wait_for(call_next(request), timeout=self.timeout)
except asyncio.TimeoutError:
return PlainTextResponse(status_code=504, content="Request timed out")
app = FastAPI()
app.add_middleware(TimeoutMiddleware, timeout=5)
@app.get("/")
async def root():
await asyncio.sleep(10) # Simulates a long-running process
return {"message": "This won't be reached if the timeout is less than 10 seconds."}
12. TrailingSlashMiddleware
Описание
Нормализует URL, добавляя или удаляя концевые косые черты, обеспечивая согласованную маршрутизацию и избегая дублирования маршрутов.
Случаи использования
- Обеспечение согласованной URL-структуры во всем приложении.
- Предотвращение проблем с маршрутизацией из-за несогласованного использования URL.
Пример
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.responses import RedirectResponse
class TrailingSlashMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
if not request.url.path.endswith("/"):
return RedirectResponse(url=f"{request.url.path}/")
return await call_next(request)
app = FastAPI()
app.add_middleware(TrailingSlashMiddleware)
@app.get("/hello/")
async def hello():
return {"message": "Hello with trailing slash!"}
13. IPWhitelistingMiddleware
Описание
Ограничивает доступ к приложению на основе IP-адреса клиента, гарантируя разрешение запросов с определенных IP-адресов.
Случаи использования
- Ограничение доступа к внутренним API.
- Добавление дополнительного уровня безопасности путем ограничения доступа по IP-адресу.
Пример
from fastapi import FastAPI, Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.responses import PlainTextResponse
class IPWhitelistMiddleware(BaseHTTPMiddleware):
def __init__(self, app, whitelist):
super().__init__(app)
self.whitelist = whitelist
async def dispatch(self, request: Request, call_next):
client_ip = request.client.host
if client_ip not in self.whitelist:
return PlainTextResponse(status_code=403, content="IP not allowed")
return await call_next(request)
app = FastAPI()
app.add_middleware(IPWhitelistMiddleware, whitelist=["127.0.0.1", "192.168.1.1"])
@app.get("/")
async def root():
return {"message": "Your IP is whitelisted!"}
14. ProxyHeadersMiddleware
Описание
Используется, когда приложение работает через прокси-сервер, например Nginx, или API-шлюз. Считывает заголовки, установленные прокси (например, X-Forwarded-For, X-Forwarded-Proto), чтобы определить исходный IP и схему клиента.
Случаи использования
- Правильное определение IP-адреса клиента при работе через прокси-сервер.
- Обработка завершения HTTPS на уровне прокси.
Пример
from fastapi import FastAPI, Request
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
app = FastAPI()
app.add_middleware(ProxyHeadersMiddleware)
@app.get("/")
async def root(request: Request):
return {"client_ip": request.client.host}
15. CSRFMiddleware
Описание
Обеспечивает FastAPI-приложению CSRF-защиту (CSRF — cross-site request forgery — межсайтовая подделка запросов), генерируя и проверяя CSRF-токены. Это помогает предотвратить выполнение несанкционированных команд от имени аутентифицированного пользователя.
Для использования в FastAPI-приложении промежуточной программы CSRFMiddleware надо установить пакет:
pip install starlette-csrf
Случаи использования
- Защита форм и действий от CSRF-атак.
- Обеспечение выполнения только легитимных действий аутентифицированными пользователями.
Пример
from fastapi import FastAPI, Request
from starlette_csrf import CSRFMiddleware
app = FastAPI()
app.add_middleware(CSRFMiddleware, secret="__CHANGE_ME__")
@app.get("/")
async def root(request: Request):
return {"message": request.cookies.get('csrftoken')}
16. StarletteContextMiddleware
Описание
starlette-context — стороннее промежуточное ПО, используемое в FastAPI (и Starlette) для поддержания и управления контекстом с привязкой к запросу. Оно позволяет хранить и извлекать информацию, специфичную для одного запроса, например заголовки запросов, информацию о пользователе или идентификаторы корреляции, не передавая эти данные через каждую функцию или обработчик маршрута в явном виде.
Это особенно полезно в сложных приложениях, где определенные данные должны быть доступны в течение всего времени выполнения запроса, но необходимо избежать их явной передачи через параметры функции.
Для использования промежуточного ПО starlette-context в FastAPI-приложении надо установить пакет:
pip install starlette-context
Случаи использования
- Автоматическая фиксация в журналах деталей, относящихся к конкретному запросу (например, идентификатора корреляции).
- Хранение метаданных, которые относятся к конкретному запросу и должны быть доступны в разных частях приложения.
- Отслеживание информации о пользователях на разных уровнях приложения (например, в службах или операциях с базой данных).
Пример
from fastapi import FastAPI, Depends
from fastapi.responses import JSONResponse
from starlette_context.middleware import ContextMiddleware
from starlette_context import context
app = FastAPI()
app.add_middleware(ContextMiddleware)
async def set_globals() -> None:
context["username"] = "chris"
@app.get("/", dependencies=[Depends(set_globals)])
async def info():
return JSONResponse(context.data)
17. GlobalsMiddleware
GlobalsMiddleware — еще одно стороннее промежуточное ПО, похожее на starlette-context, но ориентированное на обеспечение глобального управления состоянием в ASGI-приложениях подобно тому, как это делает объект g для flask-приложений.
Для использования промежуточного ПО fastapi-g-context в FastAPI-приложении нужно установить пакет:
pip install fastapi-g-context
Случаи использования
- Хранение настроек всего приложения или состояния, к которому необходимо получить доступ из различных частей приложения.
- Хранение и получение данных, относящихся к конкретному запросу, без необходимости передавать их через несколько уровней приложения.
Пример
from fastapi import FastAPI, Depends
from fastapi_g_context import GlobalsMiddleware, g
app = FastAPI()
app.add_middleware(GlobalsMiddleware)
async def set_globals() -> None:
g.username = "JohnDoe"
g.request_id = "123456"
g.is_admin = True
@app.get("/", dependencies=[Depends(set_globals)])
async def info():
return {"username": g.username, "request_id": g.request_id, "is_admin": g.is_admin}
Заключение
Промежуточное ПО — неотъемлемая часть разработки FastAPI-приложений — предлагает множество способов оптимизировать и защитить API. Встроенные промежуточные модули, предоставляемые FastAPI и Starlette, охватывают широкий спектр необходимых функций — от CORS-обработки и управления сессиями до обеспечения безопасных HTTPS-соединений и защиты от CSRF-угроз. Кроме того, возможность интегрировать стороннее промежуточное ПО или создавать свои решения обеспечивает еще большую гибкость, позволяя адаптировать приложение под конкретные нужды.
Читайте также:
- FastAPI, Flask или Streamlit: что выбрать для веб-разработки?
- Python FastAPI: OpenAPI, CRUD, PostgreSQL в Docker и внедрение зависимостей
- Роль сервисной сетки и шлюзов API в архитектуре микросервисов
Читайте нас в Telegram, VK и Дзен
Перевод статьи Chris Karvouniaris: 17 Useful Middlewares for FastAPI that You Should Know About





