Принимать сжатое тело в FastAPI / Uvicorn

Я использую FastAPI с Uvicorn для реализации u-сервиса, который принимает полезные данные json в теле запроса. Поскольку тело запроса может быть довольно большим, я хочу, чтобы служба принимала gzip-архивы. Как мне этого добиться?

Пока что следующее:

  • добавлено GZipMiddleware, но оно кодирует ответы, а не запросы декодирования
  • добавил "Content-Encoding: gzip" к моему запросу

Ошибка с ответом:

Статус: 400 неверный запрос
{подробно: при синтаксическом анализе тела произошла ошибка}


person bavaza    schedule 30.11.2020    source источник


Ответы (1)


FastAPI документация, содержит пример пользовательского класса запроса кодирования gzip.

Примечание. Эта страница также содержит следующую фразу: ... если вам нужна поддержка Gzip, вы можете использовать предоставленное GzipMiddleware., но это неверно, поскольку вы правильно заметили это промежуточное ПО работает только для ответов.

import gzip
from typing import Callable, List

from fastapi import Body, FastAPI, Request, Response
from fastapi.routing import APIRoute


class GzipRequest(Request):
    async def body(self) -> bytes:
        if not hasattr(self, "_body"):
            body = await super().body()
            if "gzip" in self.headers.getlist("Content-Encoding"):
                body = gzip.decompress(body)
            self._body = body
        return self._body


class GzipRoute(APIRoute):
    def get_route_handler(self) -> Callable:
        original_route_handler = super().get_route_handler()

        async def custom_route_handler(request: Request) -> Response:
            request = GzipRequest(request.scope, request.receive)
            return await original_route_handler(request)

        return custom_route_handler


app = FastAPI()
app.router.route_class = GzipRoute


@app.post("/sum")
async def sum_numbers(numbers: List[int] = Body(...)):
    return {"sum": sum(numbers)}
person alex_noname    schedule 30.11.2020
comment
Хм. Интересно, зачем реализовывать это как маршрутизатор, а не как промежуточное ПО. Это просто для примера или есть другие соображения? - person bavaza; 02.12.2020
comment
Мне тоже кажется, что это было для примера. Для этого существует открытая проблема - person alex_noname; 02.12.2020