mirror of https://github.com/tiangolo/fastapi.git
🌐 Update translations for uk (add-missing) (#15158)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
9671f78d29
commit
dc689a9ee3
|
|
@ -0,0 +1,63 @@
|
|||
# JSON з байтами як Base64 { #json-with-bytes-as-base64 }
|
||||
|
||||
Якщо ваш застосунок має отримувати і надсилати дані JSON, але потрібно включати туди двійкові дані, ви можете кодувати їх як base64.
|
||||
|
||||
## Base64 проти файлів { #base64-vs-files }
|
||||
|
||||
Насамперед розгляньте, чи можете ви використати [Файли запиту](../tutorial/request-files.md) для завантаження двійкових даних і [Користувацька відповідь - FileResponse](./custom-response.md#fileresponse--fileresponse-) для надсилання двійкових даних замість кодування їх у JSON.
|
||||
|
||||
JSON може містити лише строки, закодовані в UTF-8, тому він не може містити «сирі» байти.
|
||||
|
||||
Base64 може кодувати двійкові дані у строках, але для цього потрібно більше символів, ніж у початкових двійкових даних, тож зазвичай це менш ефективно, ніж звичайні файли.
|
||||
|
||||
Використовуйте base64 лише якщо справді потрібно включати двійкові дані в JSON і ви не можете використати файли для цього.
|
||||
|
||||
## Pydantic `bytes` { #pydantic-bytes }
|
||||
|
||||
Ви можете оголосити модель Pydantic з полями `bytes`, а потім використати `val_json_bytes` у конфігурації моделі, щоб вказати їй використовувати base64 для перевірки вхідних даних JSON; як частина цієї перевірки, вона декодує строку base64 у байти.
|
||||
|
||||
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
|
||||
|
||||
Якщо ви перевірите `/docs`, там буде показано, що поле `data` очікує байти, закодовані в base64:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/json-base64-bytes/image01.png">
|
||||
</div>
|
||||
|
||||
Ви можете надіслати запит так:
|
||||
|
||||
```json
|
||||
{
|
||||
"description": "Some data",
|
||||
"data": "aGVsbG8="
|
||||
}
|
||||
```
|
||||
|
||||
/// tip | Порада
|
||||
|
||||
`aGVsbG8=` - це кодування base64 для `hello`.
|
||||
|
||||
///
|
||||
|
||||
Після цього Pydantic декодує строку base64 і надасть вам початкові байти в полі моделі `data`.
|
||||
|
||||
Ви отримаєте відповідь приблизно таку:
|
||||
|
||||
```json
|
||||
{
|
||||
"description": "Some data",
|
||||
"content": "hello"
|
||||
}
|
||||
```
|
||||
|
||||
## Pydantic `bytes` для вихідних даних { #pydantic-bytes-for-output-data }
|
||||
|
||||
Ви також можете використовувати поля `bytes` з `ser_json_bytes` у конфігурації моделі для вихідних даних, і Pydantic серіалізує байти як base64 під час формування відповіді JSON.
|
||||
|
||||
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
|
||||
|
||||
## Pydantic `bytes` для вхідних і вихідних даних { #pydantic-bytes-for-input-and-output-data }
|
||||
|
||||
І, звісно, ви можете використовувати ту саму модель, налаштовану на base64, щоб обробляти і вхідні дані (перевіряти) з `val_json_bytes`, і вихідні дані (серіалізувати) з `ser_json_bytes` під час отримання та надсилання даних JSON.
|
||||
|
||||
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
# Потокова передача даних { #stream-data }
|
||||
|
||||
Якщо ви хочете передавати потоком дані, які можна структурувати як JSON, див. [Потокова передача JSON Lines](../tutorial/stream-json-lines.md).
|
||||
|
||||
Але якщо ви хочете передавати потоком чисті бінарні дані або строки, ось як це зробити.
|
||||
|
||||
/// info | Інформація
|
||||
|
||||
Додано у 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 }
|
||||
|
||||
У наведених вище прикладах байти даних передавалися потоком, але у відповіді не було заголовка `Content-Type`, тому клієнт не знав, який тип даних він отримує.
|
||||
|
||||
Можна створити власний підклас `StreamingResponse`, який встановлює заголовок `Content-Type` відповідно до типу даних, що ви стрімите.
|
||||
|
||||
Наприклад, можна створити `PNGStreamingResponse`, який встановлює заголовок `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`.
|
||||
|
||||
І часто їх читання є блокувальною операцією (що може блокувати цикл подій), адже дані зчитуються з диска або мережі.
|
||||
|
||||
/// info | Інформація
|
||||
|
||||
Наведений вище приклад - виняток, адже об'єкт `io.BytesIO` вже в пам'яті, тож читання нічого не блокує.
|
||||
|
||||
Але в багатьох випадках читання файлу або схожого на файл об'єкта блокує виконання.
|
||||
|
||||
///
|
||||
|
||||
Щоб уникнути блокування циклу подій, просто оголосіть функцію операції шляху зі звичайним `def` замість `async def`. Тоді FastAPI виконуватиме її в працівнику пулу потоків, щоб не блокувати головний цикл.
|
||||
|
||||
{* ../../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] *}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
# Сувора перевірка Content-Type { #strict-content-type-checking }
|
||||
|
||||
За замовчуванням **FastAPI** використовує сувору перевірку заголовка `Content-Type` для тіл запитів JSON, це означає, що запити JSON мають включати дійсний заголовок `Content-Type` (наприклад, `application/json`), щоб тіло було розібране як JSON.
|
||||
|
||||
## Ризик CSRF { #csrf-risk }
|
||||
|
||||
Ця поведінка за замовчуванням забезпечує захист від класу атак **Cross-Site Request Forgery (CSRF)** у дуже конкретному сценарії.
|
||||
|
||||
Ці атаки використовують той факт, що браузери дозволяють скриптам надсилати запити без виконання перевірки CORS preflight, коли вони:
|
||||
|
||||
* не мають заголовка `Content-Type` (наприклад, використовуючи `fetch()` з тілом типу `Blob`)
|
||||
* і не надсилають жодних облікових даних автентифікації.
|
||||
|
||||
Такий тип атаки головним чином актуальний, коли:
|
||||
|
||||
* застосунок працює локально (наприклад, на `localhost`) або у внутрішній мережі
|
||||
* і в застосунку немає жодної автентифікації, очікується, що будь-який запит з тієї ж мережі є надійним.
|
||||
|
||||
## Приклад атаки { #example-attack }
|
||||
|
||||
Уявіть, що ви створюєте спосіб запускати локального AI-агента.
|
||||
|
||||
Він надає API за адресою
|
||||
|
||||
```
|
||||
http://localhost:8000/v1/agents/multivac
|
||||
```
|
||||
|
||||
Є також фронтенд за адресою
|
||||
|
||||
```
|
||||
http://localhost:8000
|
||||
```
|
||||
|
||||
/// tip | Порада
|
||||
|
||||
Зауважте, що обидва мають один і той самий хост.
|
||||
|
||||
///
|
||||
|
||||
Використовуючи фронтенд, ви можете змушувати AI-агента виконувати дії від вашого імені.
|
||||
|
||||
Оскільки він працює локально, а не у відкритому інтернеті, ви вирішуєте не налаштовувати жодної автентифікації, просто покладаючись на доступ до локальної мережі.
|
||||
|
||||
Один із ваших користувачів може встановити його і запустити локально.
|
||||
|
||||
Потім він може відкрити шкідливий вебсайт, напр. щось на кшталт
|
||||
|
||||
```
|
||||
https://evilhackers.example.com
|
||||
```
|
||||
|
||||
І цей шкідливий вебсайт надсилає запити, використовуючи `fetch()` з тілом типу `Blob`, до локального API за адресою
|
||||
|
||||
```
|
||||
http://localhost:8000/v1/agents/multivac
|
||||
```
|
||||
|
||||
Хоча хости шкідливого вебсайту та локального застосунку різні, браузер не запустить CORS preflight-запит, тому що:
|
||||
|
||||
* Застосунок працює без будь-якої автентифікації, немає потреби надсилати облікові дані.
|
||||
* Браузер вважає, що він не надсилає JSON (через відсутній заголовок `Content-Type`).
|
||||
|
||||
Тоді шкідливий вебсайт може змусити локального AI-агента надсилати злі повідомлення колишньому босу користувача... або щось гірше. 😅
|
||||
|
||||
## Відкритий інтернет { #open-internet }
|
||||
|
||||
Якщо ваш застосунок у відкритому інтернеті, ви не стали б «довіряти мережі» і дозволяти кому завгодно надсилати привілейовані запити без автентифікації.
|
||||
|
||||
Зловмисники можуть просто запустити скрипт, щоб надсилати запити до вашого API, без будь-якої участі браузера, тож ви, ймовірно, вже захищаєте будь-які привілейовані ендпоїнти.
|
||||
|
||||
У такому разі ця атака/ризик до вас не застосовується.
|
||||
|
||||
Цей ризик і атака головним чином актуальні, коли застосунок працює в локальній мережі і це єдиний передбачуваний захист.
|
||||
|
||||
## Дозволення запитів без Content-Type { #allowing-requests-without-content-type }
|
||||
|
||||
Якщо вам потрібно підтримувати клієнтів, які не надсилають заголовок `Content-Type`, ви можете вимкнути сувору перевірку, встановивши `strict_content_type=False`:
|
||||
|
||||
{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}
|
||||
|
||||
З цим налаштуванням запити без заголовка `Content-Type` матимуть тіло, розібране як JSON, що відповідає поведінці старіших версій FastAPI.
|
||||
|
||||
/// info | Інформація
|
||||
|
||||
Цю поведінку і конфігурацію додано у FastAPI 0.132.0.
|
||||
|
||||
///
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Підтримка редакторів { #editor-support }
|
||||
|
||||
Офіційне [FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) покращує ваш робочий процес розробки FastAPI завдяки виявленню й навігації по *операціях шляху*, а також розгортанню у FastAPI Cloud і потоковому передаванню журналів у реальному часі.
|
||||
|
||||
Докладніше про розширення дивіться у README в [репозиторії GitHub](https://github.com/fastapi/fastapi-vscode).
|
||||
|
||||
## Налаштування та встановлення { #setup-and-installation }
|
||||
|
||||
**FastAPI Extension** доступне для [VS Code](https://code.visualstudio.com/) і [Cursor](https://www.cursor.com/). Його можна встановити безпосередньо з панелі Extensions у кожному редакторі, знайшовши «FastAPI» і вибравши розширення від **FastAPI Labs**. Розширення також працює у браузерних редакторах, таких як [vscode.dev](https://vscode.dev) і [github.dev](https://github.dev).
|
||||
|
||||
### Виявлення застосунку { #application-discovery }
|
||||
|
||||
Типово розширення автоматично виявляє застосунки FastAPI у вашому робочому просторі, скануючи файли, які створюють екземпляр `FastAPI()`. Якщо автовиявлення не працює для структури вашого проєкту, ви можете вказати точку входу через `[tool.fastapi]` у `pyproject.toml` або налаштування VS Code `fastapi.entryPoint`, використовуючи нотацію модуля (наприклад, `myapp.main:app`).
|
||||
|
||||
## Можливості { #features }
|
||||
|
||||
- **Провідник операцій шляху** - Бічне деревоподібне представлення всіх <dfn title="маршрути, кінцеві точки">*операцій шляху*</dfn> у вашому застосунку. Натисніть, щоб перейти до будь-якого визначення маршруту або маршрутизатора.
|
||||
- **Пошук маршрутів** - Пошук за шляхом, методом або назвою за допомогою <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>).
|
||||
- **Навігація CodeLens** - Клікабельні посилання над викликами тестового клієнта (наприклад, `client.get('/items')`), які переходять до відповідної *операції шляху* для швидкої навігації між тестами та реалізацією.
|
||||
- **Розгортання у FastAPI Cloud** - Розгортання вашого застосунку у [FastAPI Cloud](https://fastapicloud.com/) в один клік.
|
||||
- **Потокове передавання журналів застосунку** - Потокове передавання журналів у реальному часі з вашого застосунку, розгорнутого у FastAPI Cloud, з фільтруванням за рівнем і пошуком по тексту.
|
||||
|
||||
Щоб ознайомитися з можливостями розширення, відкрийте Палітру команд (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> або на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>), виберіть «Welcome: Open walkthrough...», а потім «Get started with FastAPI».
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
# Події, надіслані сервером (SSE) { #server-sent-events-sse }
|
||||
|
||||
Ви можете транслювати дані клієнту за допомогою **Server-Sent Events** (SSE).
|
||||
|
||||
Це подібно до [Потік JSON Lines](stream-json-lines.md), але використовує формат `text/event-stream`, який нативно підтримується браузерами через [API `EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
|
||||
|
||||
/// info | Інформація
|
||||
|
||||
Додано у FastAPI 0.135.0.
|
||||
|
||||
///
|
||||
|
||||
## Що таке Server-Sent Events { #what-are-server-sent-events }
|
||||
|
||||
SSE - це стандарт для трансляції даних із сервера до клієнта по HTTP.
|
||||
|
||||
Кожна подія - це невеликий текстовий блок із «полями» на кшталт `data`, `event`, `id` та `retry`, розділений порожніми рядками.
|
||||
|
||||
Виглядає так:
|
||||
|
||||
```
|
||||
data: {"name": "Portal Gun", "price": 999.99}
|
||||
|
||||
data: {"name": "Plumbus", "price": 32.99}
|
||||
|
||||
```
|
||||
|
||||
SSE часто використовують для стрімінгу чатів ШІ, живих сповіщень, логів і спостережуваності, а також інших випадків, коли сервер надсилає оновлення клієнту.
|
||||
|
||||
/// tip | Порада
|
||||
|
||||
Якщо ви хочете транслювати бінарні дані, наприклад відео чи аудіо, перегляньте просунутий посібник: [Потік даних](../advanced/stream-data.md).
|
||||
|
||||
///
|
||||
|
||||
## Стрімінг SSE у FastAPI { #stream-sse-with-fastapi }
|
||||
|
||||
Щоб транслювати SSE з FastAPI, використовуйте `yield` у вашій *функції операції шляху* і встановіть `response_class=EventSourceResponse`.
|
||||
|
||||
Імпортуйте `EventSourceResponse` з `fastapi.sse`:
|
||||
|
||||
{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}
|
||||
|
||||
Кожен елемент, повернений через `yield`, кодується як JSON і надсилається в полі `data:` події SSE.
|
||||
|
||||
Якщо ви оголосите тип повернення як `AsyncIterable[Item]`, FastAPI використає його, щоб **перевіряти**, **документувати** і **серіалізувати** дані за допомогою Pydantic.
|
||||
|
||||
{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}
|
||||
|
||||
/// tip | Порада
|
||||
|
||||
Оскільки Pydantic серіалізує це на боці **Rust**, ви отримаєте значно вищу **продуктивність**, ніж якби не оголошували тип повернення.
|
||||
|
||||
///
|
||||
|
||||
### Не-async *функції операцій шляху* { #non-async-path-operation-functions }
|
||||
|
||||
Ви також можете використовувати звичайні функції `def` (без `async`) і використовувати `yield` так само.
|
||||
|
||||
FastAPI подбає про коректне виконання, щоб воно не блокувало цикл подій.
|
||||
|
||||
Оскільки в цьому випадку функція не async, коректним типом повернення буде `Iterable[Item]`:
|
||||
|
||||
{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}
|
||||
|
||||
### Без типу повернення { #no-return-type }
|
||||
|
||||
Можна також опустити тип повернення. FastAPI використає [`jsonable_encoder`](./encoder.md), щоб конвертувати дані і надіслати їх.
|
||||
|
||||
{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}
|
||||
|
||||
## `ServerSentEvent` { #serversentevent }
|
||||
|
||||
Якщо вам потрібно встановити поля SSE, такі як `event`, `id`, `retry` або `comment`, ви можете повертати через `yield` об'єкти `ServerSentEvent` замість звичайних даних.
|
||||
|
||||
Імпортуйте `ServerSentEvent` з `fastapi.sse`:
|
||||
|
||||
{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}
|
||||
|
||||
Поле `data` завжди кодується як JSON. Ви можете передати будь-яке значення, яке можна серіалізувати в JSON, включно з моделями Pydantic.
|
||||
|
||||
## Сирі дані { #raw-data }
|
||||
|
||||
Якщо потрібно надіслати дані **без** кодування в JSON, використовуйте `raw_data` замість `data`.
|
||||
|
||||
Це корисно для надсилання попередньо відформатованого тексту, рядків логів або спеціальних значень <dfn title="Значення, яке використовується для позначення особливої умови або стану">«значення-сторож»</dfn>, як-от `[DONE]`.
|
||||
|
||||
{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}
|
||||
|
||||
/// note | Примітка
|
||||
|
||||
`data` і `raw_data` взаємовиключні. У кожному `ServerSentEvent` ви можете встановити лише одне з них.
|
||||
|
||||
///
|
||||
|
||||
## Відновлення з `Last-Event-ID` { #resuming-with-last-event-id }
|
||||
|
||||
Коли браузер перепідключається після розриву з'єднання, він надсилає останній отриманий `id` у заголовку `Last-Event-ID`.
|
||||
|
||||
Ви можете прочитати його як параметр заголовка і використати, щоб відновити потік із місця, де клієнт зупинився:
|
||||
|
||||
{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}
|
||||
|
||||
## SSE з POST { #sse-with-post }
|
||||
|
||||
SSE працює з **будь-яким HTTP-методом**, не лише з `GET`.
|
||||
|
||||
Це корисно для протоколів на кшталт [MCP](https://modelcontextprotocol.io), які транслюють SSE через `POST`:
|
||||
|
||||
{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}
|
||||
|
||||
## Технічні деталі { #technical-details }
|
||||
|
||||
FastAPI реалізує деякі найкращі практики SSE «з коробки».
|
||||
|
||||
- Надсилати **коментар «keep alive» `ping`** кожні 15 секунд, коли не було жодного повідомлення, щоб запобігти закриттю з'єднання деякими проксі, як рекомендовано у [Специфікації HTML: Події, надіслані сервером](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes).
|
||||
- Встановити заголовок `Cache-Control: no-cache`, щоб **запобігти кешуванню** потоку.
|
||||
- Встановити спеціальний заголовок `X-Accel-Buffering: no`, щоб **запобігти буферизації** у деяких проксі, наприклад Nginx.
|
||||
|
||||
Вам не потрібно нічого з цим робити, воно працює «з коробки». 🤓
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
# Стрімінг JSON Lines { #stream-json-lines }
|
||||
|
||||
У вас може бути послідовність даних, яку ви хочете надсилати у **«потоці»**, це можна зробити за допомогою **JSON Lines**.
|
||||
|
||||
/// info | Інформація
|
||||
|
||||
Додано в FastAPI 0.134.0.
|
||||
|
||||
///
|
||||
|
||||
## Що таке потік { #what-is-a-stream }
|
||||
|
||||
«**Стрімінг**» даних означає, що ваш застосунок почне надсилати елементи даних клієнту, не чекаючи, доки буде готова вся послідовність елементів.
|
||||
|
||||
Тобто він надішле перший елемент, клієнт його отримає і почне обробляти, а ви в цей час уже можете створювати наступний елемент.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant App
|
||||
participant Client
|
||||
|
||||
App->>App: Produce Item 1
|
||||
App->>Client: Send Item 1
|
||||
App->>App: Produce Item 2
|
||||
Client->>Client: Process Item 1
|
||||
App->>Client: Send Item 2
|
||||
App->>App: Produce Item 3
|
||||
Client->>Client: Process Item 2
|
||||
App->>Client: Send Item 3
|
||||
Client->>Client: Process Item 3
|
||||
Note over App: Keeps producing...
|
||||
Note over Client: Keeps consuming...
|
||||
```
|
||||
|
||||
Це може бути навіть нескінченний потік, у якому ви постійно надсилаєте дані.
|
||||
|
||||
## JSON Lines { #json-lines }
|
||||
|
||||
У таких випадках часто надсилають «**JSON Lines**» - формат, у якому ви надсилаєте по одному об’єкту JSON на рядок.
|
||||
|
||||
Відповідь матиме тип вмісту `application/jsonl` (замість `application/json`), а тіло буде приблизно таким:
|
||||
|
||||
```json
|
||||
{"name": "Plumbus", "description": "A multi-purpose household device."}
|
||||
{"name": "Portal Gun", "description": "A portal opening device."}
|
||||
{"name": "Meeseeks Box", "description": "A box that summons a Meeseeks."}
|
||||
```
|
||||
|
||||
Це дуже схоже на масив JSON (еквівалент списку Python), але замість того, щоб бути загорнутим у `[]` і мати `,` між елементами, тут є **по одному об’єкту JSON на рядок**, вони розділені символом нового рядка.
|
||||
|
||||
/// info | Інформація
|
||||
|
||||
Важливо те, що ваш застосунок зможе по черзі створювати кожен рядок, поки клієнт споживає попередні рядки.
|
||||
|
||||
///
|
||||
|
||||
/// note | Технічні деталі
|
||||
|
||||
Оскільки кожен об’єкт JSON буде розділено новим рядком, він не може містити буквальні символи нового рядка у своєму вмісті, але може містити екрановані нові рядки (`\n`), що є частиною стандарту JSON.
|
||||
|
||||
Зазвичай про це не треба турбуватися, усе робиться автоматично, читайте далі. 🤓
|
||||
|
||||
///
|
||||
|
||||
## Випадки використання { #use-cases }
|
||||
|
||||
Ви можете використовувати це, щоб стрімити дані зі служби **AI LLM**, із **логів** чи **телеметрії**, або з інших типів даних, які можна структурувати як елементи **JSON**.
|
||||
|
||||
/// tip | Порада
|
||||
|
||||
Якщо ви хочете стрімити бінарні дані, наприклад відео чи аудіо, перегляньте просунутий посібник: [Потокова передача даних](../advanced/stream-data.md).
|
||||
|
||||
///
|
||||
|
||||
## Стрімінг JSON Lines з FastAPI { #stream-json-lines-with-fastapi }
|
||||
|
||||
Щоб стрімити JSON Lines з FastAPI, замість використання `return` у вашій *функції операції шляху* використовуйте `yield`, щоб по черзі створювати кожен елемент.
|
||||
|
||||
{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}
|
||||
|
||||
Якщо кожен елемент JSON, який ви хочете надіслати у відповідь, має тип `Item` (модель Pydantic) і це async-функція, ви можете оголосити тип повернення як `AsyncIterable[Item]`:
|
||||
|
||||
{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}
|
||||
|
||||
Якщо ви оголосите тип повернення, FastAPI використає його, щоб **перевіряти** дані, **документувати** їх в OpenAPI, **фільтрувати** їх і **серіалізувати** за допомогою Pydantic.
|
||||
|
||||
/// tip | Порада
|
||||
|
||||
Оскільки Pydantic серіалізуватиме це на боці **Rust**, ви отримаєте значно вищу **продуктивність**, ніж якби не оголошували тип повернення.
|
||||
|
||||
///
|
||||
|
||||
### Не-async *функції операцій шляху* { #non-async-path-operation-functions }
|
||||
|
||||
Ви також можете використовувати звичайні функції `def` (без `async`) і використовувати `yield` так само.
|
||||
|
||||
FastAPI подбає про коректне виконання, щоб це не блокувало цикл подій.
|
||||
|
||||
Оскільки в цьому випадку функція не є async, правильним типом повернення буде `Iterable[Item]`:
|
||||
|
||||
{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}
|
||||
|
||||
### Без типу повернення { #no-return-type }
|
||||
|
||||
Ви також можете опустити тип повернення. Тоді FastAPI використає [`jsonable_encoder`](./encoder.md), щоб перетворити дані на щось, що можна серіалізувати в JSON, і потім надішле їх як JSON Lines.
|
||||
|
||||
{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}
|
||||
|
||||
## Події, надіслані сервером (SSE) { #server-sent-events-sse }
|
||||
|
||||
FastAPI також має повноцінну підтримку Server-Sent Events (SSE), які досить схожі, але мають кілька додаткових деталей. Ви можете дізнатися про них у наступному розділі: [Події, надіслані сервером (SSE)](server-sent-events.md). 🤓
|
||||
Loading…
Reference in New Issue