Chunked Transfer — това е механизъм на HTTP протокола, при който сървърът предава тялото на отговора на отделни фрагменти (парчета), без да посочва предварително общия размер на данните. Всяко парче съдържа своя размер в шестнадесетичен формат и данни с определена дължина, а завършва с финално парче с нулев размер. Според MDN Web Docs, 2025, Transfer-Encoding: chunked се включва автоматично от сървъра, когато размерът на отговора не е известен предварително — например при генериране на съдържание в движение или поточно предаване на данни.
Основни точки
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 MB нагоре.
В 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 KB, 8 KB или 16 KB. Оптималният размер на парчето е кратен на размера на TCP сегмента (обикновено 1460 байта за Ethernet), за да се минимизира фрагментацията на транспортно ниво. Nginx по подразбиране използва парчета от 4 KB, Apache — от 8 KB.
Клиентът, получил Transfer-Encoding: chunked, е длъжен да чете отговора парче по парче до крайното нулево парче. Ако клиентът не поддържа chunked transfer, сървърът не може да използва този режим. На практика всички съвременни HTTP клиенти — браузъри, OkHttp, URLSession, curl — напълно поддържат chunked отговори. Поточното четене позволява на клиента да започне обработка на данните, преди да получи пълния отговор, което е критично за производителността.
| Елемент на парчето | Формат | Пример |
|---|---|---|
| Размер на парчето | HEX + CRLF | 1000 |
| Данни на парчето | [размер байта] + CRLF | [4096 байта данни] |
| Крайно парче | 0 | 0 |
| Trailer (по избор) | Заглавки + CRLF | Expires: Wed, 21 Oct 2025 |
Chunked Transfer поддържа trailer заглавки — допълнителни HTTP заглавки, които се предават след последното парче. Това е полезно за метаданни, които стават известни едва след завършване на генерирането на отговора: например Content-MD5 или X-Compression-Ratio. Trailer заглавките трябва да бъдат декларирани в заглавката Trailer: Content-MD5, X-Compression-Ratio. На практика trailer се използват рядко — повечето сървъри не ги включват в отговорите.
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 ) уведомява клиента за края на предаването.
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("Chunk: $line")
}
reader.close()
}
OkHttp напълно абстрахира програмиста от детайлите на Chunked Transfer. При получаване на отговор с Transfer-Encoding: chunked, OkHttp автоматично събира парчетата и предоставя на програмиста пълното тяло на отговора чрез response.body?.string(). За поточна обработка се използва response.body?.source(), който връща BufferedSource и позволява четене на данните при постъпването им. Програмистът не трябва ръчно да анализира hex размери и CRLF — библиотеката прави това автоматично.
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 по принцип не може да бъде изчислен предварително. Динамични отчети, генерирани по заявка на потребителя с филтриране и агрегиране — сървърът не знае обема на данните до завършване на заявката към базата данни. Поточно видео, предавано от камера в реално време — размерът е безкраен. SSE и long polling за известия — отговорът може да продължи неопределено дълго. Във всички тези случаи Chunked Transfer е единственият правилен механизъм.
Chunked Transfer стои в основата на много поточни технологии в уеб. Най-известната е Server-Sent Events (SSE), при която сървърът изпраща събития на клиента чрез една HTTP връзка с Transfer-Encoding: chunked. SSE използва специален текстов формат (data: съобщение ), но транспортният слой е обикновен chunked transfer. Браузърът получава събития, когато се изпращат от сървъра, без да чака завършване на отговора.
Поточното аудио и видео също разчита на Chunked Transfer. Медийни сървъри като Nginx RTMP и Wowza Streaming Engine изпращат медийни данни на парчета чрез HTTP. Плейърът от страна на клиента започва възпроизвеждане, когато бъде получено първото парче, без да чака пълно зареждане на файла. Това намалява времето до началото на възпроизвеждане (Time to First Frame) от десетки секунди на 1-2 секунди. YouTube и Netflix използват точно този подход за своите HTTP потоци.
В разработката на мобилни приложения Chunked Transfer се използва за предаване на големи обеми данни без зареждане на целия отговор в паметта. При зареждане на изображения чрез Coil или Glide на Android, библиотеките четат поточни данни на парчета и постепенно декодират изображението. Това позволява показване на големи изображения (10+ MB) без OutOfMemoryError. OkHttp поддържа поточно четене чрез response.body?.byteStream(), който връща InputStream, четящ данни парче по парче.
gRPC използва HTTP/2, където поточното предаване е вградено на ниво протокол и не изисква отделен chunked механизъм. GraphQL сървъри, работещи чрез HTTP/1.1, могат да използват Chunked Transfer за поточно предаване на резултати от абонаменти (subscriptions). Apollo Server и Hasura изпращат chunked отговори за GraphQL абонаменти, предавайки събития, когато възникнат. Клиентът получава актуализации в реално време без необходимост от polling.
Chunked Transfer предоставя важни предимства за уеб приложения. Незабавно изпращане на данни — сървърът не буферира отговора преди изпращане, намалявайки закъснението (latency) до първия байт. Поточна обработка — клиентът може да започне обработка на данните при постъпването им, без да чака пълно зареждане. Без ограничения на паметта — сървърът не съхранява пълния отговор в паметта, което е критично за големи обеми данни. Възможност за предаване на безкрайни потоци — SSE, живо видео, мониторинг.
Въпреки това 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 не се използва за upload в HTTP/1.1. На iOS URLSession поддържа както изпращане, така и получаване на chunked данни без специална конфигурация. Поточното анализиране на JSON (например чрез Jackson Streaming API или Moshi) позволява обработка на големи JSON масиви при постъпването на chunked потока.
Често задавани въпроси
Сървърът включва Chunked Transfer автоматично, когато размерът на отговора не е известен. Nginx добавя Transfer-Encoding: chunked, ако не е зададен Content-Length. В Spring Boot StreamingResponseBody и SseEmitter автоматично използват chunked transfer. В Node.js Express отговорът става chunked, ако се извикат res.write() и res.end() без Content-Length.
Не, спецификацията HTTP/1.1 забранява едновременното използване на Content-Length и Transfer-Encoding: chunked. Ако сървърът изпрати и двете заглавки, клиентът трябва да игнорира Content-Length и да обработи отговора като chunked. Това правило е установено в RFC 7230 за съвместимост с прокси сървъри, които могат да променят тялото на отговора.
Оптималният размер на парчето зависи от сценария. За обикновени уеб страници — 4-8 KB. За поточно видео — 16-64 KB. За SSE — минимални парчета от 1-2 KB за намаляване на закъснението. Размерът на парчето трябва да бъде кратен на размера на TCP сегмента (1460 байта за Ethernet) за минимизиране на фрагментацията на транспортно ниво.
Съвременните прокси сървъри (Nginx, HAProxy, Envoy) поддържат Chunked Transfer. Проксито може да предава парчетата без буфериране (streaming) или да буферира целия отговор и да го изпрати отново с Content-Length. Старите прокси могат да буферират chunked отговора до завършване, което увеличава закъснението. HTTP/2 решава този проблем на ниво протокол.
Това е едно и също нещо. Chunked Transfer е пълното име на механизма от спецификацията HTTP/1.1. HTTP chunked encoding е същото, понякога използвано в документацията на библиотеки. Transfer-Encoding: chunked е заглавката, която включва този режим. И трите термина описват един и същ механизъм за предаване на данни на части.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също