Skip to content

Commit 27559e8

Browse files
🌐 Update translations for uk (add-missing)
1 parent fa63a15 commit 27559e8

6 files changed

Lines changed: 522 additions & 0 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# JSON з байтами як Base64 { #json-with-bytes-as-base64 }
2+
3+
Якщо ваш застосунок має отримувати і надсилати дані JSON, але потрібно включати туди двійкові дані, ви можете кодувати їх як base64.
4+
5+
## Base64 проти файлів { #base64-vs-files }
6+
7+
Насамперед розгляньте, чи можете ви використати [Файли запиту](../tutorial/request-files.md) для завантаження двійкових даних і [Користувацька відповідь - FileResponse](./custom-response.md#fileresponse--fileresponse-) для надсилання двійкових даних замість кодування їх у JSON.
8+
9+
JSON може містити лише строки, закодовані в UTF-8, тому він не може містити «сирі» байти.
10+
11+
Base64 може кодувати двійкові дані у строках, але для цього потрібно більше символів, ніж у початкових двійкових даних, тож зазвичай це менш ефективно, ніж звичайні файли.
12+
13+
Використовуйте base64 лише якщо справді потрібно включати двійкові дані в JSON і ви не можете використати файли для цього.
14+
15+
## Pydantic `bytes` { #pydantic-bytes }
16+
17+
Ви можете оголосити модель Pydantic з полями `bytes`, а потім використати `val_json_bytes` у конфігурації моделі, щоб вказати їй використовувати base64 для перевірки вхідних даних JSON; як частина цієї перевірки, вона декодує строку base64 у байти.
18+
19+
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
20+
21+
Якщо ви перевірите `/docs`, там буде показано, що поле `data` очікує байти, закодовані в base64:
22+
23+
<div class="screenshot">
24+
<img src="/img/tutorial/json-base64-bytes/image01.png">
25+
</div>
26+
27+
Ви можете надіслати запит так:
28+
29+
```json
30+
{
31+
"description": "Some data",
32+
"data": "aGVsbG8="
33+
}
34+
```
35+
36+
/// tip | Порада
37+
38+
`aGVsbG8=` - це кодування base64 для `hello`.
39+
40+
///
41+
42+
Після цього Pydantic декодує строку base64 і надасть вам початкові байти в полі моделі `data`.
43+
44+
Ви отримаєте відповідь приблизно таку:
45+
46+
```json
47+
{
48+
"description": "Some data",
49+
"content": "hello"
50+
}
51+
```
52+
53+
## Pydantic `bytes` для вихідних даних { #pydantic-bytes-for-output-data }
54+
55+
Ви також можете використовувати поля `bytes` з `ser_json_bytes` у конфігурації моделі для вихідних даних, і Pydantic серіалізує байти як base64 під час формування відповіді JSON.
56+
57+
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
58+
59+
## Pydantic `bytes` для вхідних і вихідних даних { #pydantic-bytes-for-input-and-output-data }
60+
61+
І, звісно, ви можете використовувати ту саму модель, налаштовану на base64, щоб обробляти і вхідні дані (перевіряти) з `val_json_bytes`, і вихідні дані (серіалізувати) з `ser_json_bytes` під час отримання та надсилання даних JSON.
62+
63+
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Потокова передача даних { #stream-data }
2+
3+
Якщо ви хочете передавати потоком дані, які можна структурувати як JSON, див. [Потокова передача JSON Lines](../tutorial/stream-json-lines.md).
4+
5+
Але якщо ви хочете передавати потоком чисті бінарні дані або строки, ось як це зробити.
6+
7+
/// info | Інформація
8+
9+
Додано у FastAPI 0.134.0.
10+
11+
///
12+
13+
## Варіанти використання { #use-cases }
14+
15+
Це можна використовувати, якщо ви хочете передавати потоком чисті строки, наприклад безпосередньо з виводу сервісу AI LLM.
16+
17+
Також це можна використати для потокової передачі великих бінарних файлів, коли ви надсилаєте кожний фрагмент даних під час читання, без потреби завантажувати все в пам'ять одразу.
18+
19+
Так само можна стрімити відео чи аудіо; їх навіть можна генерувати під час обробки та надсилання.
20+
21+
## `StreamingResponse` з `yield` { #a-streamingresponse-with-yield }
22+
23+
Якщо ви оголосите `response_class=StreamingResponse` у вашій функції операції шляху, ви можете використовувати `yield`, щоб послідовно надсилати кожний фрагмент даних.
24+
25+
{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}
26+
27+
FastAPI передаватиме кожний фрагмент даних до `StreamingResponse` як є; він не намагатиметься перетворити його на JSON чи щось подібне.
28+
29+
### Не-async функції операції шляху { #non-async-path-operation-functions }
30+
31+
Можна також використовувати звичайні функції `def` (без `async`) і так само застосовувати `yield`.
32+
33+
{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}
34+
35+
### Без анотації { #no-annotation }
36+
37+
Для потокової передачі бінарних даних немає потреби оголошувати анотацію типу, що повертається.
38+
39+
Оскільки FastAPI не намагатиметься перетворювати дані на JSON за допомогою Pydantic чи серіалізувати їх іншим чином, у цьому випадку анотація типу потрібна лише для вашого редактора та інструментів; FastAPI її не використовуватиме.
40+
41+
{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}
42+
43+
Це також означає, що з `StreamingResponse` у вас є свобода і відповідальність формувати та кодувати байти даних саме так, як їх потрібно надіслати, незалежно від анотацій типів. 🤓
44+
45+
### Потік байтів { #stream-bytes }
46+
47+
Один з основних сценаріїв - передавати потоком `bytes` замість строк; це, звісно, підтримується.
48+
49+
{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}
50+
51+
## Користувацький `PNGStreamingResponse` { #a-custom-pngstreamingresponse }
52+
53+
У наведених вище прикладах байти даних передавалися потоком, але у відповіді не було заголовка `Content-Type`, тому клієнт не знав, який тип даних він отримує.
54+
55+
Можна створити власний підклас `StreamingResponse`, який встановлює заголовок `Content-Type` відповідно до типу даних, що ви стрімите.
56+
57+
Наприклад, можна створити `PNGStreamingResponse`, який встановлює заголовок `Content-Type` у `image/png` за допомогою атрибута `media_type`:
58+
59+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}
60+
61+
Потім ви можете використати цей новий клас у `response_class=PNGStreamingResponse` у вашій функції операції шляху:
62+
63+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}
64+
65+
### Симулювати файл { #simulate-a-file }
66+
67+
У цьому прикладі ми імітуємо файл за допомогою `io.BytesIO` - це об'єкт на кшталт файлу, який існує лише в пам'яті, але надає той самий інтерфейс.
68+
69+
Наприклад, ми можемо ітеруватися по ньому, щоб зчитати вміст, так само як і з файлом.
70+
71+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}
72+
73+
/// note | Технічні деталі
74+
75+
Інші дві змінні, `image_base64` та `binary_image`, - це зображення, закодоване в Base64, яке потім перетворюється на байти, щоб передати його в `io.BytesIO`.
76+
77+
Лише для того, щоб усе містилося в одному файлі для цього прикладу, і ви могли скопіювати його та запустити як є. 🥚
78+
79+
///
80+
81+
Використовуючи блок `with`, ми гарантуємо, що об'єкт, подібний до файлу, буде закрито після завершення генераторної функції (функції з `yield`). Тобто після завершення надсилання відповіді.
82+
83+
У цьому конкретному прикладі це не так важливо, адже це фальшивий файл у пам'яті (з `io.BytesIO`), але для справжнього файлу важливо переконатися, що файл закрито після завершення роботи з ним.
84+
85+
### Файли та async { #files-and-async }
86+
87+
У більшості випадків об'єкти, подібні до файлів, за замовчуванням несумісні з `async` та `await`.
88+
89+
Наприклад, у них немає `await file.read()` або `async for chunk in file`.
90+
91+
І часто їх читання є блокувальною операцією (що може блокувати цикл подій), адже дані зчитуються з диска або мережі.
92+
93+
/// info | Інформація
94+
95+
Наведений вище приклад - виняток, адже об'єкт `io.BytesIO` вже в пам'яті, тож читання нічого не блокує.
96+
97+
Але в багатьох випадках читання файлу або схожого на файл об'єкта блокує виконання.
98+
99+
///
100+
101+
Щоб уникнути блокування циклу подій, просто оголосіть функцію операції шляху зі звичайним `def` замість `async def`. Тоді FastAPI виконуватиме її в працівнику пулу потоків, щоб не блокувати головний цикл.
102+
103+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}
104+
105+
/// tip | Порада
106+
107+
Якщо вам потрібно викликати блокувальний код усередині async-функції або async-функцію зсередини блокувальної функції, ви можете скористатися [Asyncer](https://asyncer.tiangolo.com) - спорідненою бібліотекою до FastAPI.
108+
109+
///
110+
111+
### `yield from` { #yield-from }
112+
113+
Коли ви ітеруєтеся по чомусь, наприклад по об'єкту, подібному до файлу, і робите `yield` для кожного елемента, можна також використати `yield from`, щоб віддавати кожен елемент напряму і пропустити цикл `for`.
114+
115+
Це не специфічно для FastAPI, це просто Python, але корисний трюк. 😎
116+
117+
{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Сувора перевірка Content-Type { #strict-content-type-checking }
2+
3+
За замовчуванням **FastAPI** використовує сувору перевірку заголовка `Content-Type` для тіл запитів JSON, це означає, що запити JSON мають включати дійсний заголовок `Content-Type` (наприклад, `application/json`), щоб тіло було розібране як JSON.
4+
5+
## Ризик CSRF { #csrf-risk }
6+
7+
Ця поведінка за замовчуванням забезпечує захист від класу атак **Cross-Site Request Forgery (CSRF)** у дуже конкретному сценарії.
8+
9+
Ці атаки використовують той факт, що браузери дозволяють скриптам надсилати запити без виконання перевірки CORS preflight, коли вони:
10+
11+
* не мають заголовка `Content-Type` (наприклад, використовуючи `fetch()` з тілом типу `Blob`)
12+
* і не надсилають жодних облікових даних автентифікації.
13+
14+
Такий тип атаки головним чином актуальний, коли:
15+
16+
* застосунок працює локально (наприклад, на `localhost`) або у внутрішній мережі
17+
* і в застосунку немає жодної автентифікації, очікується, що будь-який запит з тієї ж мережі є надійним.
18+
19+
## Приклад атаки { #example-attack }
20+
21+
Уявіть, що ви створюєте спосіб запускати локального AI-агента.
22+
23+
Він надає API за адресою
24+
25+
```
26+
http://localhost:8000/v1/agents/multivac
27+
```
28+
29+
Є також фронтенд за адресою
30+
31+
```
32+
http://localhost:8000
33+
```
34+
35+
/// tip | Порада
36+
37+
Зауважте, що обидва мають один і той самий хост.
38+
39+
///
40+
41+
Використовуючи фронтенд, ви можете змушувати AI-агента виконувати дії від вашого імені.
42+
43+
Оскільки він працює локально, а не у відкритому інтернеті, ви вирішуєте не налаштовувати жодної автентифікації, просто покладаючись на доступ до локальної мережі.
44+
45+
Один із ваших користувачів може встановити його і запустити локально.
46+
47+
Потім він може відкрити шкідливий вебсайт, напр. щось на кшталт
48+
49+
```
50+
https://evilhackers.example.com
51+
```
52+
53+
І цей шкідливий вебсайт надсилає запити, використовуючи `fetch()` з тілом типу `Blob`, до локального API за адресою
54+
55+
```
56+
http://localhost:8000/v1/agents/multivac
57+
```
58+
59+
Хоча хости шкідливого вебсайту та локального застосунку різні, браузер не запустить CORS preflight-запит, тому що:
60+
61+
* Застосунок працює без будь-якої автентифікації, немає потреби надсилати облікові дані.
62+
* Браузер вважає, що він не надсилає JSON (через відсутній заголовок `Content-Type`).
63+
64+
Тоді шкідливий вебсайт може змусити локального AI-агента надсилати злі повідомлення колишньому босу користувача... або щось гірше. 😅
65+
66+
## Відкритий інтернет { #open-internet }
67+
68+
Якщо ваш застосунок у відкритому інтернеті, ви не стали б «довіряти мережі» і дозволяти кому завгодно надсилати привілейовані запити без автентифікації.
69+
70+
Зловмисники можуть просто запустити скрипт, щоб надсилати запити до вашого API, без будь-якої участі браузера, тож ви, ймовірно, вже захищаєте будь-які привілейовані ендпоїнти.
71+
72+
У такому разі ця атака/ризик до вас не застосовується.
73+
74+
Цей ризик і атака головним чином актуальні, коли застосунок працює в локальній мережі і це єдиний передбачуваний захист.
75+
76+
## Дозволення запитів без Content-Type { #allowing-requests-without-content-type }
77+
78+
Якщо вам потрібно підтримувати клієнтів, які не надсилають заголовок `Content-Type`, ви можете вимкнути сувору перевірку, встановивши `strict_content_type=False`:
79+
80+
{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}
81+
82+
З цим налаштуванням запити без заголовка `Content-Type` матимуть тіло, розібране як JSON, що відповідає поведінці старіших версій FastAPI.
83+
84+
/// info | Інформація
85+
86+
Цю поведінку і конфігурацію додано у FastAPI 0.132.0.
87+
88+
///

0 commit comments

Comments
 (0)