# Потоковая передача данных { #stream-data }

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

Но если вы хотите передавать в потоке чистые бинарные данные или строки, ниже показано, как это сделать.

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

Добавлено в FastAPI 0.134.0.

///

## Варианты использования { #use-cases }

Это можно использовать, если вы хотите стримить чистые строки, например, напрямую из вывода сервиса **AI LLM**.

Также вы можете стримить **большие бинарные файлы**, передавая каждый чанк данных по мере чтения, без необходимости загружать всё в память сразу.

Аналогично можно стримить **видео** или **аудио** — данные могут даже генерироваться по мере обработки и отправки.

## «`StreamingResponse` с `yield`» { #a-streamingresponse-with-yield }

Если вы укажете `response_class=StreamingResponse` в своей *функции-обработчике пути*, вы можете использовать `yield`, чтобы по очереди отправлять каждый чанк данных.

{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}

FastAPI будет передавать каждый чанк данных в `StreamingResponse` как есть, не пытаясь конвертировать его в JSON или что-то подобное.

### Не-async *функции-обработчики пути* { #non-async-path-operation-functions }

Можно использовать и обычные функции `def` (без `async`) и точно так же применять `yield`.

{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}

### Без аннотации { #no-annotation }

Для потоковой передачи бинарных данных вам не нужно указывать аннотацию типа возвращаемого значения.

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

{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}

Это также означает, что с `StreamingResponse` у вас есть и свобода, и ответственность — производить и кодировать байты данных ровно в том виде, в котором они должны быть отправлены, независимо от аннотаций типов. 🤓

### Потоковая передача байтов { #stream-bytes }

Один из основных сценариев — стримить `bytes` вместо строк, и, конечно, это можно сделать.

{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}

## Пользовательский `PNGStreamingResponse` { #a-custom-pngstreamingresponse }

В примерах выше байты данных передавались потоком, но в ответе не было HTTP-заголовка `Content-Type`, поэтому клиент не знал, какой тип данных он получает.

Вы можете создать пользовательский подкласс `StreamingResponse`, который устанавливает HTTP-заголовок `Content-Type` в тип данных, которые вы стримите.

Например, вы можете создать `PNGStreamingResponse`, который устанавливает HTTP-заголовок `Content-Type` в `image/png` с помощью атрибута `media_type`:

{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}

Затем вы можете использовать этот новый класс в `response_class=PNGStreamingResponse` в своей *функции-обработчике пути*:

{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}

### Симулировать файл { #simulate-a-file }

В этом примере мы симулируем файл с помощью `io.BytesIO` — это «файлоподобный» объект, который существует только в памяти, но позволяет использовать тот же интерфейс.

Например, мы можем итерироваться по нему, чтобы потреблять его содержимое, как и по обычному файлу.

{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}

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

Две другие переменные, `image_base64` и `binary_image`, — это изображение, закодированное в Base64, а затем преобразованное в байты, после чего переданное в `io.BytesIO`.

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

///

Используя блок `with`, мы гарантируем, что объект, ведущий себя как файл, будет закрыт после завершения работы функции‑генератора (функции с `yield`). То есть после того, как она закончит отправку ответа.

В этом конкретном примере это не столь важно, потому что это «фейковый» файл в памяти (`io.BytesIO`), но для реального файла важно удостовериться, что файл закрыт после завершения работы с ним.

### Файлы и async { #files-and-async }

В большинстве случаев «файлоподобные» объекты по умолчанию не совместимы с async и await.

Например, у них нет `await file.read()` или `async for chunk in file`.

И во многих случаях чтение таких объектов будет блокирующей операцией (которая может заблокировать цикл событий), потому что данные читаются с диска или из сети.

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

Приведённый выше пример — исключение, потому что объект `io.BytesIO` уже находится в памяти, поэтому чтение ничего не блокирует.

Но во многих случаях чтение файла или «файлоподобного» объекта будет блокировать.

///

Чтобы не блокировать цикл событий, вы можете просто объявить *функцию-обработчик пути* обычной `def` вместо `async def`. Тогда FastAPI выполнит её в воркере из пула потоков (threadpool), чтобы не блокировать основной цикл.

{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}

/// tip | Совет

Если вам нужно вызвать блокирующий код изнутри async-функции, или async-функцию изнутри блокирующей функции, вы можете использовать [Asyncer](https://asyncer.tiangolo.com), родственную библиотеку к FastAPI.

///

### `yield from` { #yield-from }

Когда вы итерируетесь по чему‑то, например, по «файлоподобному» объекту, и делаете `yield` для каждого элемента, вы можете также использовать `yield from`, чтобы отдавать каждый элемент напрямую и не писать цикл `for`.

Это не специфично для FastAPI, это просто Python, но полезный приём. 😎

{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}
