Промежуточное ПО играет важную роль в веб-фреймворках, выступая в качестве слоя обработки, который находится между входящими запросами и исходящими ответами. Этот слой может изменять запросы, обрабатывать исключения, управлять сессиями, сжимать ответы и многое другое. В 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