Chunked Transfer у веб-розробці — що це, формат і принцип передачі частинами

Автор: IT Sectr Опубліковано: 2026-03-10 Час читання: 9 хв

Chunked Transfer — це механізм HTTP-протоколу, при якому сервер передає тіло відповіді окремими фрагментами (частинами), не вказуючи заздалегідь загальний розмір даних. Кожна частина містить свій розмір у шістнадцятковому форматі та дані вказаної довжини, а завершується фінальною частиною нульового розміру. За даними MDN Web Docs, 2025, Transfer-Encoding: chunked вмикається сервером автоматично, коли розмір відповіді невідомий заздалегідь — наприклад, при генерації контенту на льоту або потоковій передачі даних.

Головне

  • Chunked Transfer — передача HTTP-відповіді частинами без попереднього вказання Content-Length.
  • Transfer-Encoding: chunked — заголовок, що вмикає режим передачі даних частинами.
  • Кожна частина містить розмір у hex, дані та завершальний CRLF, а кінець позначається частиною нульового розміру.
  • Streaming — основне застосування chunked transfer для передачі аудіо, відео та SSE-подій.
  • Chunked Transfer несумісний із заголовком Content-Length — одночасно вони не використовуються.

Що таке Chunked Transfer?

Chunked Transfer — це механізм HTTP, визначений у специфікації HTTP/1.1 (RFC 7230, розділ 4.1), який дозволяє серверу надсилати тіло відповіді частинами без вказання загального Content-Length. Замість обчислення розміру відповіді перед відправкою, сервер починає передачу негайно, надсилаючи фрагменти даних у міру їх готовності. Кожен фрагмент супроводжується власним заголовком розміру, що дозволяє клієнту збирати відповідь з частин.

Механізм вмикається заголовком Transfer-Encoding: chunked. Коли клієнт бачить цей заголовок у відповіді, він знає, що тіло буде передаватися частинами, і повинен читати відповідь у циклі: прочитати розмір частини, потім прочитати дані вказаного розміру, потім повторити. Процес завершується, коли зустрічається частина нульового розміру. Chunked Transfer — обов'язкова частина HTTP/1.1, підтримувана всіма сучасними веб-серверами та HTTP-клієнтами.

Головна причина використання chunked transfer — динамічна генерація контенту. Коли сервер генерує відповідь на основі запиту до бази даних, зовнішнього API або тривалого обчислення, він не може заздалегідь знати розмір результату. Замість буферизації всієї відповіді в пам'яті (що ризиковано для великих обсягів), сервер вмикає Transfer-Encoding: chunked і надсилає дані в міру готовності. Це особливо важливо для серверів з обмеженою пам'яттю та для відповідей, розмір яких може бути дуже великим — від 100 МБ і вище.

Різниця між HTTP/1.1 chunked та HTTP/2

В HTTP/2 механізм chunked transfer як такий відсутній, оскільки протокол використовує мультиплексування потоків на рівні фреймів. В HTTP/2 дані будь-якого розміру передаються у фреймах DATA, і розмір тіла відповіді не потрібно оголошувати заздалегідь — потік може бути закритий у будь-який момент. Сучасні сервери автоматично перетворюють chunked-відповіді HTTP/1.1 в еквівалентну потокову передачу при проксуванні на HTTP/2 upstream. Chunked Transfer залишається актуальним для HTTP/1.1-з'єднань.

Як працює передача частинами

Коли сервер вирішує використовувати Chunked Transfer, він не обчислює Content-Length, а надсилає заголовок Transfer-Encoding: chunked. Далі тіло відповіді формується як послідовність частин. Кожна частина починається з рядка, що містить розмір частини у шістнадцятковому форматі (без префікса 0x), за яким слідує CRLF ( ). Потім ідуть дані частини вказаного розміру, що завершуються CRLF. Остання частина має розмір 0, після якого можуть слідувати trailer-заголовки.

Шістнадцятковий розмір дозволяє передавати частини будь-якого розміру від 1 байта до теоретично необмеженого обсягу. На практиці розмір частини вибирається сервером: типові значення — 4 КБ, 8 КБ або 16 КБ. Оптимальний розмір частини кратний розміру TCP-сегмента (зазвичай 1460 байт для Ethernet), щоб мінімізувати фрагментацію на транспортному рівні. Nginx використовує частини по 4 КБ за замовчуванням, Apache — по 8 КБ.

Клієнт, який отримав Transfer-Encoding: chunked, зобов'язаний читати відповідь частина за частиною до завершальної нульової частини. Якщо клієнт не підтримує chunked transfer, сервер не може використовувати цей режим. На практиці всі сучасні HTTP-клієнти — браузери, OkHttp, URLSession, curl — повністю підтримують chunked-відповіді. Потокове читання дозволяє клієнту почати обробку даних до отримання повної відповіді, що критично важливо для продуктивності.

Елемент частиниФорматПриклад
Розмір частиниHEX + CRLF1000
Дані частини[розмір байт] + CRLF[4096 байт даних]
Завершальна частина0 0
Trailer (опціонально)Заголовки + CRLFExpires: Wed, 21 Oct 2025

Trailer-заголовки в Chunked Transfer

Chunked Transfer підтримує trailer-заголовки — додаткові HTTP-заголовки, які передаються після останньої частини. Це корисно для метаданих, які стають відомі тільки після завершення генерації відповіді: наприклад, Content-MD5 або X-Compression-Ratio. Trailer-заголовки повинні бути оголошені в заголовку Trailer: Trailer: Content-MD5, X-Compression-Ratio. На практиці trailer використовуються рідко — більшість серверів не включає їх у відповіді.

Формат chunked-відповіді

Chunked-відповідь має строго визначену структуру, яку клієнт повинен коректно розібрати. Розглянемо повний приклад HTTP-відповіді з Transfer-Encoding: chunked. Після заголовків і порожнього рядка починається тіло відповіді. Структура тіла являє собою послідовність: розмір_частини дані розмір_частини дані ... до 0 . Кожен розмір передається у шістнадцятковій системі числення ASCII-символами.

Приклад відповіді сервера з Chunked Transfer:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

7
Hello
6
World!
0

У цьому прикладі сервер передає рядок «Hello World!» двома частинами. Перша частина розміром 7 байт містить «Hello », друга — 6 байт «World!». Клієнт збирає дані з обох частин і отримує повний рядок. Важливо: розмір частини включає тільки дані, не включаючи CRLF-розділювачі самих частин. Завершальна порожня частина (0 ) повідомляє клієнту про закінчення передачі.

kotlin
import java.net.HttpURLConnection
import java.io.BufferedReader
import java.io.InputStreamReader

fun readChunkedResponse() {
    val url = java.net.URL("https://stream.example.com/data")
    val connection = url.openConnection() as HttpURLConnection
    val reader = BufferedReader(
        InputStreamReader(connection.inputStream)
    )

    var line: String?
    while (reader.readLine().also { line = it } != null) {
        println("Частина: $line")
    }
    reader.close()
}

Розбір chunked-відповіді в OkHttp

OkHttp повністю абстрагує розробника від деталей Chunked Transfer. При отриманні відповіді з Transfer-Encoding: chunked OkHttp автоматично збирає частини та надає розробнику повне тіло відповіді через response.body?.string(). Для потокової обробки використовується response.body?.source(), який повертає BufferedSource і дозволяє читати дані в міру надходження. Розробнику не потрібно вручну розбирати hex-розміри та CRLF — бібліотека робить це автоматично.

Chunked Transfer vs Content-Length

Content-Length і Transfer-Encoding: chunked — два взаємовиключних способи вказати розмір тіла HTTP-повідомлення. Content-Length — це заголовок, який містить точний розмір тіла в байтах. Він обов'язковий для відповідей, розмір яких відомий заздалегідь, і для запитів з тілом (POST, PUT). Content-Length дозволяє клієнту заздалегідь виділити буфер потрібного розміру та перевірити, чи отримані всі дані.

Chunked Transfer використовується, коли розмір тіла заздалегідь невідомий. Це відбувається в трьох основних сценаріях: динамічна генерація контенту (наприклад, запит до БД, результат якого ще не отримано), потокова передача великих файлів (щоб не буферизувати весь файл у пам'яті) та Server-Sent Events (SSE) для передачі подій у реальному часі. Вибір між Content-Length і chunked — відповідальність сервера. Якщо сервер знає розмір до початку передачі, він повинен використовувати Content-Length як простіший і передбачуваніший механізм.

Специфікація HTTP/1.1 забороняє одночасне використання Content-Length і Transfer-Encoding: chunked. Якщо сервер надсилає обидва заголовки, клієнт повинен ігнорувати Content-Length і обробляти відповідь як chunked. Пріоритет Transfer-Encoding над Content-Length встановлено в RFC 7230 для випадків, коли проксі-сервер модифікує тіло відповіді та не може зберегти вихідний Content-Length. Деякі старі HTTP-клієнти некоректно обробляють цю ситуацію, але сучасні реалізації слідують специфікації.

Коли Content-Length неможливий

Існують сценарії, в яких Content-Length принципово не може бути розрахований заздалегідь. Динамічні звіти, що генеруються на запит користувача з фільтрацією та агрегацією — сервер не знає обсяг даних до завершення запиту до БД. Потокове відео, що передається з камери в реальному часі — розмір нескінченний. SSE та long polling для сповіщень — відповідь може тривати невизначено довго. У всіх цих випадках Chunked Transfer — єдиний коректний механізм.

Streaming на основі chunked transfer

Chunked Transfer лежить в основі багатьох потокових технологій у вебі. Найвідоміша — Server-Sent Events (SSE), де сервер надсилає події клієнту через одне HTTP-з'єднання з Transfer-Encoding: chunked. SSE використовує спеціальний текстовий формат (data: повідомлення ), але транспортний рівень — звичайний chunked transfer. Браузер отримує події в міру їх надсилання сервером, не чекаючи завершення відповіді.

Streaming аудіо та відео також спирається на Chunked Transfer. Медіа-сервери, такі як Nginx RTMP і Wowza Streaming Engine, надсилають медіадані частинами через HTTP. Плеєр на стороні клієнта починає відтворення, коли отримано першу частину, не чекаючи повного завантаження файлу. Це скорочує час до початку відтворення з десятків секунд до 1-2 секунд. YouTube і Netflix використовують саме цей підхід для своїх HTTP-потоків.

У мобільній розробці Chunked Transfer використовується для передачі великих обсягів даних без завантаження всієї відповіді в пам'ять. При завантаженні зображень через Coil або Glide на Android бібліотеки читають потокові дані частинами та поступово декодують зображення. Це дозволяє відображати великі зображення (10+ МБ) без OutOfMemoryError. OkHttp підтримує потокове читання через response.body?.byteStream(), який повертає InputStream, що читає дані частина за частиною.

Chunked transfer в gRPC та GraphQL

gRPC використовує HTTP/2, де потокова передача вбудована на рівні протоколу та не потребує окремого механізму chunked. GraphQL-сервери, що працюють через HTTP/1.1, можуть використовувати Chunked Transfer для потокової передачі результатів підписок (subscriptions). Apollo Server і Hasura надсилають chunked-відповіді для GraphQL-підписок, передаючи події в міру їх виникнення. Клієнт отримує оновлення в реальному часі без необхідності поллінгу.

Переваги та обмеження

Chunked Transfer надає важливі переваги для веб-додатків. Негайне надсилання даних — сервер не буферизує відповідь перед надсиланням, знижуючи затримку до першого байта. Потокова обробка — клієнт може почати обробляти дані в міру надходження, не чекаючи повного завантаження. Відсутність обмежень по пам'яті — сервер не зберігає повну відповідь у пам'яті, що критично для великих обсягів даних. Можливість передачі нескінченних потоків — SSE, live-відео, моніторинг.

Однак у Chunked Transfer є обмеження. Накладні витрати на кожну частину становлять 6-12 байт на розмір + CRLF, що для великої кількості дрібних частин (наприклад, по 100 байт) може збільшити розмір відповіді на 10-15%. Неможливість вказати точний розмір — клієнт не може заздалегідь виділити буфер або показати прогрес-бар. Проблеми з проксі-серверами — деякі старі проксі не підтримують chunked transfer і не можуть кешувати такі відповіді. Відсутність підтримки відновлення завантаження — для частково отриманих chunked-відповідей не можна зробити Range-запит.

За даними HTTP Archive, 2025, близько 35% всіх HTTP-відповідей використовують Transfer-Encoding: chunked. Серед них переважають динамічні сторінки (60%), API-відповіді (25%) та медіапотоки (15%). Статичні файли практично завжди використовують Content-Length, оскільки їх розмір відомий заздалегідь. Частка chunked-відповідей поступово знижується з поширенням HTTP/2, де потокова передача реалізована на рівні фреймів без необхідності в додатковому заголовку Transfer-Encoding.

Практичні рекомендації

У мобільній розробці використовуйте Chunked Transfer для завантаження великих файлів (зображення, відео) та для API-запитів, що повертають великі масиви даних. OkHttp повністю підтримує chunked transfer без додаткового налаштування. Для завантаження на сервер (upload) Chunked Transfer не застосовується — для цього Transfer-Encoding не використовується в HTTP/1.1. На iOS URLSession підтримує як надсилання, так і отримання chunked-даних без спеціальної конфігурації. Потоковий парсинг JSON (наприклад, через Jackson Streaming API або Moshi) дозволяє обробляти великі JSON-масиви в міру надходження chunked-потоку.

Поширені запитання

Як сервер вмикає Chunked Transfer?

Сервер вмикає Chunked Transfer автоматично, коли розмір відповіді невідомий. Nginx додає Transfer-Encoding: chunked, якщо не задано Content-Length. У Spring Boot StreamingResponseBody та SseEmitter автоматично використовують chunked transfer. У Node.js Express відповідь стає chunked, якщо викликати res.write() та res.end() без Content-Length.

Чи можна використовувати Content-Length і chunked одночасно?

Ні, специфікація HTTP/1.1 забороняє одночасне використання Content-Length і Transfer-Encoding: chunked. Якщо сервер надсилає обидва заголовки, клієнт повинен ігнорувати Content-Length і обробляти відповідь як chunked. Це правило встановлено в RFC 7230 для сумісності з проксі-серверами, які можуть змінювати тіло відповіді.

Який розмір частини оптимальний?

Оптимальний розмір частини залежить від сценарію. Для звичайних веб-сторінок — 4-8 КБ. Для потокової передачі відео — 16-64 КБ. Для SSE — мінімальні частини по 1-2 КБ для зниження затримки. Розмір частини повинен бути кратним розміру TCP-сегмента (1460 байт для Ethernet) для мінімізації фрагментації на транспортному рівні.

Чи працює Chunked Transfer через проксі?

Сучасні проксі-сервери (Nginx, HAProxy, Envoy) підтримують Chunked Transfer. Проксі може передавати частини далі без буферизації (streaming) або буферизувати всю відповідь і перевідправити з Content-Length. Старі проксі можуть буферизувати chunked-відповідь до завершення, що збільшує затримку. HTTP/2 вирішує цю проблему на рівні протоколу.

Чим Chunked Transfer відрізняється від HTTP chunked encoding?

Це одне й те саме. Chunked Transfer — це повна назва механізму зі специфікації HTTP/1.1. HTTP chunked encoding — те саме, іноді використовується в документації бібліотек. Transfer-Encoding: chunked — заголовок, який вмикає цей режим. Всі три терміни описують один і той же механізм передачі даних частинами.

Підсумки

  • Chunked Transfer — механізм HTTP/1.1, що передає тіло відповіді частинами без попереднього вказання Content-Length.
  • Transfer-Encoding: chunked — заголовок, що вмикає передачу частинами; кожна частина містить hex-розмір, дані та CRLF.
  • Завершальна частина нульового розміру сигналізує про закінчення передачі, після неї можуть слідувати trailer-заголовки.
  • Dynamic content streaming — основне застосування: динамічні сторінки, SSE, потокове аудіо/відео, довгі звіти.
  • Content-Length і chunked взаємовиключні — специфікація забороняє одночасне використання цих заголовків.
  • Переваги — зниження затримки, економія пам'яті, можливість передачі нескінченних потоків та потокова обробка на клієнті.
  • Обмеження — накладні витрати на заголовки частин, неможливість показу прогресу, проблеми зі старими проксі-серверами.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також