# Кастомные ответы — HTML, поток, файл и другие { #custom-response-html-stream-file-others }

По умолчанию **FastAPI** возвращает ответы в формате JSON.

Вы можете переопределить это, вернув `Response` напрямую, как показано в разделе [Вернуть Response напрямую](response-directly.md).

Но если вы возвращаете `Response` напрямую (или любой его подкласс, например `JSONResponse`), данные не будут автоматически преобразованы (даже если вы объявили `response_model`), и документация не будет автоматически сгенерирована (например, со специфичным «типом содержимого» в HTTP-заголовке `Content-Type` как частью сгенерированного OpenAPI).

Но вы также можете объявить `Response`, который хотите использовать (например, любой подкласс `Response`), в декораторе операции пути, указав параметр `response_class`.

Содержимое, которое вы возвращаете из своей функции-обработчика пути, будет помещено внутрь этого `Response`.

/// note | Примечание

Если вы используете класс ответа без типа содержимого, FastAPI будет ожидать, что у вашего ответа нет содержимого, поэтому он не будет документировать формат ответа в сгенерированной документации OpenAPI.

///

## JSON-ответы { #json-responses }

По умолчанию FastAPI возвращает ответы в формате JSON.

Если вы объявите [Модель ответа](../tutorial/response-model.md), FastAPI использует её для сериализации данных в JSON с помощью Pydantic.

Если вы не объявите модель ответа, FastAPI использует `jsonable_encoder`, описанный в разделе [JSON-совместимый энкодер](../tutorial/encoder.md), и поместит результат в `JSONResponse`.

Если вы объявите `response_class` с JSON типом содержимого (`application/json`), как в случае с `JSONResponse`, данные, которые вы возвращаете, будут автоматически преобразованы (и отфильтрованы) любой Pydantic-моделью ответа (`response_model`), объявленной вами в декораторе операции пути. Но данные не будут сериализованы в JSON-байты через Pydantic; вместо этого они будут преобразованы с помощью `jsonable_encoder`, а затем переданы в класс `JSONResponse`, который сериализует их в байты, используя стандартную JSON-библиотеку Python.

### Производительность JSON { #json-performance }

Коротко: если вам нужна максимальная производительность, используйте [Модель ответа](../tutorial/response-model.md) и не объявляйте `response_class` в декораторе операции пути.

{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}

## HTML-ответ { #html-response }

Чтобы вернуть ответ с HTML напрямую из **FastAPI**, используйте `HTMLResponse`.

- Импортируйте `HTMLResponse`.
- Передайте `HTMLResponse` в параметр `response_class` вашего декоратора операции пути.

{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}

/// info | Информация

Параметр `response_class` также используется для указания «типа содержимого» ответа.

В этом случае HTTP-заголовок `Content-Type` будет установлен в `text/html`.

И это будет задокументировано как таковое в OpenAPI.

///

### Вернуть `Response` { #return-a-response }

Как показано в разделе [Вернуть Response напрямую](response-directly.md), вы также можете переопределить ответ прямо в своей операции пути, просто вернув его.

Тот же пример сверху, возвращающий `HTMLResponse`, может выглядеть так:

{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}

/// warning | Предупреждение

`Response`, возвращённый напрямую вашей функцией-обработчиком пути, не будет задокументирован в OpenAPI (например, `Content-Type` не будет задокументирован) и не будет виден в автоматически сгенерированной интерактивной документации.

///

/// info | Информация

Разумеется, фактический заголовок `Content-Type`, статус-код и т.д. возьмутся из объекта `Response`, который вы вернули.

///

### Задокументировать в OpenAPI и переопределить `Response` { #document-in-openapi-and-override-response }

Если вы хотите переопределить ответ внутри функции, но при этом задокументировать «тип содержимого» в OpenAPI, вы можете использовать параметр `response_class` И вернуть объект `Response`.

Тогда `response_class` будет использоваться только для документирования *операции пути* в OpenAPI, а ваш `Response` будет использован как есть.

#### Вернуть `HTMLResponse` напрямую { #return-an-htmlresponse-directly }

Например, это может быть что-то вроде:

{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}

В этом примере функция `generate_html_response()` уже генерирует и возвращает `Response` вместо возврата HTML в `str`.

Возвращая результат вызова `generate_html_response()`, вы уже возвращаете `Response`, который переопределит поведение **FastAPI** по умолчанию.

Но поскольку вы также передали `HTMLResponse` в `response_class`, **FastAPI** будет знать, как задокументировать это в OpenAPI и интерактивной документации как HTML с `text/html`:

<img src="/img/tutorial/custom-response/image01.png">

## Доступные ответы { #available-responses }

Ниже перечислены некоторые доступные классы ответов.

Учтите, что вы можете использовать `Response`, чтобы вернуть что угодно ещё, или даже создать собственный подкласс.

/// note | Технические детали

Вы также могли бы использовать `from starlette.responses import HTMLResponse`.

**FastAPI** предоставляет те же `starlette.responses` как `fastapi.responses` для вашего удобства как разработчика. Но большинство доступных классов ответов приходят непосредственно из Starlette.

///

### `Response` { #response }

Базовый класс `Response`, от него наследуются все остальные ответы.

Его можно возвращать напрямую.

Он принимает следующие параметры:

- `content` — `str` или `bytes`.
- `status_code` — целое число, HTTP статус-код.
- `headers` — словарь строк.
- `media_type` — строка, задающая тип содержимого. Например, `"text/html"`.

FastAPI (фактически Starlette) автоматически добавит заголовок Content-Length. Также будет добавлен заголовок Content-Type, основанный на `media_type` и с добавлением charset для текстовых типов.

{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}

### `HTMLResponse` { #htmlresponse }

Принимает текст или байты и возвращает HTML-ответ, как описано выше.

### `PlainTextResponse` { #plaintextresponse }

Принимает текст или байты и возвращает ответ в виде простого текста.

{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}

### `JSONResponse` { #jsonresponse }

Принимает данные и возвращает ответ, кодированный как `application/json`.

Это ответ по умолчанию, используемый в **FastAPI**, как было сказано выше.

/// note | Технические детали

Но если вы объявите модель ответа или тип возвращаемого значения, они будут использованы напрямую для сериализации данных в JSON, и ответ с корректным типом содержимого для JSON будет возвращён напрямую, без использования класса `JSONResponse`.

Это идеальный способ получить наилучшую производительность.

///

### `RedirectResponse` { #redirectresponse }

Возвращает HTTP-редирект. По умолчанию использует статус-код 307 (Temporary Redirect — временное перенаправление).

Вы можете вернуть `RedirectResponse` напрямую:

{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}

---

Или можно использовать его в параметре `response_class`:

{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}

Если вы сделаете так, то сможете возвращать URL напрямую из своей функции-обработчика пути.

В этом случае будет использован статус-код по умолчанию для `RedirectResponse`, то есть `307`.

---

Также вы можете использовать параметр `status_code` в сочетании с параметром `response_class`:

{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}

### `StreamingResponse` { #streamingresponse }

Принимает асинхронный генератор или обычный генератор/итератор (функцию с `yield`) и отправляет тело ответа потоково.

{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}

/// note | Технические детали

Задача `async` может быть отменена только при достижении `await`. Если `await` отсутствует, генератор (функция с `yield`) не может быть корректно отменён и может продолжить работу даже после запроса на отмену.

Так как этому небольшому примеру не нужны операторы `await`, мы добавляем `await anyio.sleep(0)`, чтобы дать циклу событий возможность обработать отмену.

Это ещё более важно для больших или бесконечных потоков.

///

/// tip | Совет

Вместо того чтобы возвращать `StreamingResponse` напрямую, вероятно, лучше следовать стилю из раздела [Передача данных потоком](./stream-data.md) - так гораздо удобнее, и отмена обрабатывается «за кулисами».

Если вы передаёте JSON Lines потоком, следуйте руководству [Поток JSON Lines](../tutorial/stream-json-lines.md).

///

### `FileResponse` { #fileresponse }

Асинхронно отправляет файл как ответ.

Для создания экземпляра принимает иной набор аргументов, чем другие типы ответов:

- `path` — путь к файлу, который будет отправлен.
- `headers` — любые дополнительные заголовки для включения, в виде словаря.
- `media_type` — строка, задающая тип содержимого. Если не задан, для определения типа содержимого будет использовано имя файла или путь.
- `filename` — если задан, будет включён в заголовок ответа `Content-Disposition`.

Файловые ответы будут содержать соответствующие заголовки `Content-Length`, `Last-Modified` и `ETag`.

{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}

Вы также можете использовать параметр `response_class`:

{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}

В этом случае вы можете возвращать путь к файлу напрямую из своей функции-обработчика пути.

## Пользовательский класс ответа { #custom-response-class }

Вы можете создать собственный класс ответа, унаследовавшись от `Response`, и использовать его.

Например, предположим, что вы хотите использовать [`orjson`](https://github.com/ijl/orjson) с некоторыми настройками.

Скажем, вы хотите, чтобы возвращался отформатированный JSON с отступами, то есть хотите использовать опцию orjson `orjson.OPT_INDENT_2`.

Вы могли бы создать `CustomORJSONResponse`. Главное, что вам нужно сделать — реализовать метод `Response.render(content)`, который возвращает содержимое как `bytes`:

{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}

Теперь вместо того, чтобы возвращать:

```json
{"message": "Hello World"}
```

...этот ответ вернёт:

```json
{
  "message": "Hello World"
}
```

Разумеется, вы наверняка найдёте гораздо более полезные способы воспользоваться этим, чем просто форматирование JSON. 😉

### `orjson` или Модель ответа { #orjson-or-response-model }

Если вы стремитесь увеличить производительность, вероятно, лучше использовать [Модель ответа](../tutorial/response-model.md), чем ответ на базе `orjson`.

С моделью ответа FastAPI использует Pydantic для сериализации данных в JSON, без промежуточных шагов, таких как преобразование через `jsonable_encoder`, которое происходило бы в любом другом случае.

А под капотом Pydantic использует те же базовые механизмы на Rust, что и `orjson`, для сериализации в JSON, так что с моделью ответа вы и так получите лучшую производительность.

## Класс ответа по умолчанию { #default-response-class }

При создании экземпляра класса **FastAPI** или `APIRouter` вы можете указать, какой класс ответа использовать по умолчанию.

Параметр, который это определяет, — `default_response_class`.

В примере ниже **FastAPI** будет использовать `HTMLResponse` по умолчанию во всех операциях пути, вместо JSON.

{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}

/// tip | Совет

Вы по-прежнему можете переопределять `response_class` в операциях пути, как и раньше.

///

## Дополнительная документация { #additional-documentation }

Вы также можете объявить тип содержимого и многие другие детали в OpenAPI с помощью `responses`: [Дополнительные ответы в OpenAPI](additional-responses.md).
