Промежуточное ПО FastAPI

Промежуточное ПО — это функция, которая выполняется до и после того, как каждый запрос достигнет обработчика маршрута.

Промежуточное ПО можно использовать для общей логики, такой как добавление логов, изменение запросов/ответов, обработка CORS и т. д.


Как работает промежуточное ПО

Поток выполнения промежуточного ПО:

  • Запрос достигает промежуточного ПО
  • Промежуточное ПО выполняет логику предварительной обработки
  • Промежуточное ПО передаёт запрос следующему промежуточному ПО или функции маршрута.
  • Функция маршрута возвращает ответ
  • Middleware выполняет логику постобработки
  • Ответ возвращается клиенту

Name Функция
Клиент Браузеры, фронтенд-приложения, Postman и т. д. отправляют HTTP-запросы в FastAPI
Запрос Объект HTTP-запроса, содержащий такие данные, как URL, Header, Body, Cookie
Middleware 1 Первый слой обработки после поступления запроса
Middleware 2 Логика обработки второго слоя
Middleware N Несколько middleware выполняются по порядку
Функция-обработчик маршрута (Path Operation) Место, где фактически выполняется бизнес-код
Фаза ответа После того как маршрут возвращает Response, ответ снова проходит через промежуточное ПО.
Промежуточное ПО возвращается в обратном порядке Ответы возвращаются в "обратном порядке"
Response response Данные, которые в конечном итоге возвращаются клиенту

Создание промежуточного ПО

Использование@app.middleware("http")Создание промежуточного ПО с помощью декораторов:

Пример

import time
from fastapi import FastAPI, Request

app = FastAPI()


@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    # 1. Предварительная обработка запроса: записать время начала
    start_time = time.time()

    # 2. Передайте запрос следующему middleware или функции маршрута
    response = await call_next(request)

    # 3. Обработка после ответа: вычислить время обработки и добавить заголовки ответа.
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response


@app.get("/")
async def root():
    return {"message": "Hello World"}

Пояснение к коду:

ЧастьОписание
@app.middleware("http")Объявите это как HTTP middleware.
request: RequestТекущий объект запроса
call_nextФункция обратного вызова, которая вызывает следующий middleware или функцию маршрута.
await call_next(request)Передайте запрос следующему слою и получите ответ

call_nextПолучениеrequestПараметры и возвращаемое значениеresponse. Вы можете вызватьcall_nextИзмените запрос перед вызовом и измените ответ после вызова.


Промежуточное ПО для логирования запросов

Следующее промежуточное ПО регистрирует базовую информацию о каждом запросе:

Пример

import time
import logging
from fastapi import FastAPI, Request

app = FastAPI()

logger = logging.getLogger("uvicorn.access")


@app.middleware("http")
async def log_requests(request: Request, call_next):
    # Записать информацию о запросе
    logger.info(fЗапрос: {request.method} {request.url})

    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time

    # Записать информацию об ответе
    logger.info(
        f"Ответ: {request.method} {request.url} "
        fКод состояния={response.status_code} затраченное время={process_time:.3f}s
    )

    return response

Порядок выполнения промежуточного ПО

Промежуточное ПО выполняется в порядке регистрации; запросы проходят через промежуточное ПО в прямом порядке, а ответы — в обратном порядке:

请求 -> 中间件A(前) -> 中间件B(前) -> 路由函数
响应 <- 中间件A(后) <- 中间件B(后) <- 路由函数

Порядок регистрации промежуточного ПО важен. Если у вас есть два промежуточных ПО A и B, и сначала регистрируется A, запрос проходит сначала через A, затем через B, но ответ проходит сначала через B, затем через A.


Использование встроенного промежуточного ПО Starlette

FastAPI наследуется от Starlette, поэтому промежуточное ПО, предоставляемое Starlette, можно использовать напрямую:

Пример

from fastapi import FastAPI
from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware

app = FastAPI()

# Принудительное перенаправление на HTTPS
app.add_middleware(HTTPSRedirectMiddleware)


@app.get("/")
async def root():
    return {"message": Доступ с использованием HTTPS}

Распространённое встроенное промежуточное ПО:

Промежуточное ПООписание
HTTPSRedirectMiddlewareПринудительно перенаправлять HTTP-запросы на HTTPS
TrustedHostMiddlewareОграничить разрешённые имена хостов
GZipMiddlewareАвтоматически сжимать содержимое ответа
CORSMiddlewareОбработка кросс-доменных запросов (подробно в следующей главе)

Промежуточное ПО для GZip-сжатия

Включение GZip-сжатия может уменьшить размер ответа и повысить скорость передачи:

Пример

from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware

app = FastAPI()

# Автоматически сжимать, когда размер ответа превышает 1000 байт
app.add_middleware(GZipMiddleware, minimum_size=1000)


@app.get("/")
async def root():
    return {"message": "Этот ответ может быть сжат с помощью GZip"}

Итог

  • Промежуточное ПО выполняет общую логику в цепочке обработки запроса/ответа.
  • Использование@app.middleware("http")Создание собственного промежуточного ПО
  • call_next(request)Передать запрос на следующий слой
  • Промежуточное ПО выполняется в порядке регистрации (запросы — в прямом порядке, ответы — в обратном порядке)
  • FastAPI/Starlette предоставляет встроенное промежуточное ПО, такое как CORS, GZip, перенаправление на HTTPS и т. д.
Другие расширения