Что такое Middleware и как его реализовать в Django и FastAPI

Ответ

Middleware — это промежуточный слой обработки, который находится между веб-сервером и представлением (view). Он позволяет выполнять сквозную логику для каждого запроса или ответа, не дублируя код в каждом обработчике.

Основные задачи Middleware:

  • Аутентификация и авторизация: Проверка прав доступа пользователя.
  • Логирование: Запись информации о запросах и ответах.
  • Обработка сессий: Управление данными сессии.
  • Добавление заголовков: Например, CORS или Content-Security-Policy.
  • Сжатие ответов: Например, с помощью Gzip.

Реализация в FastAPI

В FastAPI Middleware реализуется с помощью декоратора @app.middleware("http") для асинхронных функций.

from fastapi import FastAPI, Request
import time

app = FastAPI()

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    # Добавляем кастомный заголовок со временем обработки
    response.headers["X-Process-Time"] = str(process_time)
    return response

Реализация в Django

В Django Middleware обычно реализуется как класс с методами __init__ и __call__.

# myapp/middleware.py
class SimpleLoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Код, который выполняется перед обработкой view
        print(f"Processing request: {request.path}")

        response = self.get_response(request)

        # Код, который выполняется после обработки view
        print(f"Response status code: {response.status_code}")
        return response

# settings.py
MIDDLEWARE = [
    # ...
    'myapp.middleware.SimpleLoggingMiddleware',
    # ...
]

Ответ 18+ 🔞

Да ты посмотри, что за хуйня такая — middleware! Это ж, блядь, как будто ты в офисе сидишь, а между тобой и начальником стоит какой-то ёбаный секретарь-координатор, который каждую бумажку сначала понюхает, штамп поставит, а уж потом тебе передаст. Или наоборот — твой отчёт перед тем, как шефу уйти, тоже через него пройдёт, он там время обработки в уголке нарисует.

Зачем это, спросишь? Да чтобы не писать одно и то же в каждой функции, как последний мудак! Вот смотри:

  • Проверить, кто там пришёл — аутентификация, блядь. Не пустим какого левого в штаны.
  • Записать, кто и что делал — логирование, чтобы потом, если что, найти крайнего.
  • Сессии там подержать — чтоб пользователь не забыл, кто он такой, между запросами.
  • Заголовки навесить — типа CORS, чтобы браузер не охуел от твоих ответов.
  • Ответ сжать — Gzip'нуть, чтоб трафика меньше жрал.

Как в FastAPI это делается

Тут всё просто, как три копейки. Навесил декоратор @app.middleware("http") на функцию — и она между каждым запросом и ответом вклинится. Смотри, какой прикол:

from fastapi import FastAPI, Request
import time

app = FastAPI()

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)  # Отпускаем запрос дальше, ждём ответ
    process_time = time.time() - start_time
    # А теперь, сука, прилепим в заголовки, сколько времени всё это охуение заняло
    response.headers["X-Process-Time"] = str(process_time)
    return response

Вот и весь сказ! Запрос пошёл, view отработала, а мы тут время засекли и в ответе отметили. Красота, ёпта!

А в Django — там уже классика, блядь

Тут уже подходят с серьёзным лицом — middleware это класс, у которого есть метод __call__. Выглядит как какая-то магия, но если разобраться — проще пареной репы.

# myapp/middleware.py
class SimpleLoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response  # Запоминаем, куда дальше передавать

    def __call__(self, request):
        # Это выполнится ДО того, как view начнёт работать
        print(f"Processing request: {request.path}")  # Типа, "ой, кто-то пришёл!"

        response = self.get_response(request)  # Пускаем запрос вглубь системы

        # А это — ПОСЛЕ, когда view уже всё отдала
        print(f"Response status code: {response.status_code}")  # Смотрим, не обосрался ли кто
        return response

А чтобы эта хуйня заработала, надо в настройках прописать:

# settings.py
MIDDLEWARE = [
    # ...
    'myapp.middleware.SimpleLoggingMiddleware',  # Вот наш надзиратель
    # ...
]

И всё, теперь каждый запрос будет через этот класс пролетать, как муха через москитную сетку. Удобно, блядь! Не надо в каждой вьюхе писать print — один раз написал middleware и забыл, как страшный сон.

Вот так вот, middleware — это такой универсальный "вротберунчик" для твоего приложения. Не хочешь дублировать код — засунь его в middleware и спи спокойно. Главное — не переборщить, а то наслоишь этих прослоек, что запрос будет идти дольше, чем пиздюк до первого класса.