Chunked Transfer trong phát triển web — khái niệm, định dạng và nguyên lý truyền theo khối

Tác giả: IT Sectr Đã đăng: 2026-03-10 Thời gian đọc: 9 phút

Chunked Transfer là một cơ chế của giao thức HTTP, trong đó máy chủ truyền phần thân của phản hồi thành các đoạn riêng biệt (khối) mà không chỉ định tổng kích thước dữ liệu trước. Mỗi khối chứa kích thước của nó ở định dạng thập lục phân và dữ liệu có độ dài được chỉ định, kết thúc bằng một khối cuối cùng có kích thước bằng không. Theo MDN Web Docs, 2025, Transfer-Encoding: chunked được máy chủ tự động bật khi kích thước phản hồi không được biết trước — ví dụ: trong quá trình tạo nội dung tức thời hoặc truyền dữ liệu streaming.

Những điểm chính

  • Chunked Transfer — truyền phản hồi HTTP thành nhiều phần mà không chỉ định trước Content-Length.
  • Transfer-Encoding: chunked — tiêu đề bật chế độ truyền dữ liệu theo khối.
  • Mỗi khối chứa kích thước dạng hex, dữ liệu và CRLF kết thúc, và kết thúc được biểu thị bằng một khối có kích thước bằng không.
  • Streaming — ứng dụng chính của chunked transfer để truyền âm thanh, video và sự kiện SSE.
  • Chunked Transfer không tương thích với tiêu đề Content-Length — chúng không được sử dụng đồng thời.

Chunked Transfer là gì?

Chunked Transfer là một cơ chế HTTP được định nghĩa trong đặc tả HTTP/1.1 (RFC 7230, phần 4.1) cho phép máy chủ gửi phần thân của phản hồi thành nhiều phần mà không chỉ định tổng Content-Length. Thay vì tính toán kích thước phản hồi trước khi gửi, máy chủ bắt đầu truyền ngay lập tức, gửi các đoạn dữ liệu khi chúng sẵn sàng. Mỗi đoạn đi kèm với tiêu đề kích thước riêng, cho phép máy khách lắp ráp phản hồi từ các mảnh.

Cơ chế được kích hoạt bởi tiêu đề Transfer-Encoding: chunked. Khi máy khách thấy tiêu đề này trong phản hồi, nó biết rằng phần thân sẽ được truyền theo khối và phải đọc phản hồi trong một vòng lặp: đọc kích thước khối, sau đó đọc dữ liệu có kích thước đã chỉ định, sau đó lặp lại. Quá trình kết thúc khi gặp một khối có kích thước bằng không. Chunked Transfer là một phần bắt buộc của HTTP/1.1, được hỗ trợ bởi tất cả các máy chủ web và máy khách HTTP hiện đại.

Lý do chính để sử dụng chunked transfer là tạo nội dung động. Khi máy chủ tạo phản hồi dựa trên truy vấn cơ sở dữ liệu, API bên ngoài hoặc tính toán kéo dài, nó không thể biết trước kích thước kết quả. Thay vì lưu đệm toàn bộ phản hồi trong bộ nhớ (điều này rủi ro cho khối lượng lớn), máy chủ bật Transfer-Encoding: chunked và gửi dữ liệu khi có sẵn. Điều này đặc biệt quan trọng đối với máy chủ có bộ nhớ hạn chế và cho các phản hồi có kích thước rất lớn — từ 100 MB trở lên.

Sự khác biệt giữa HTTP/1.1 chunked và HTTP/2

Trong HTTP/2, cơ chế chunked transfer như vậy không tồn tại vì giao thức sử dụng ghép kênh luồng ở cấp khung. Trong HTTP/2, dữ liệu ở mọi kích thước được truyền trong các khung DATA và kích thước phần thân phản hồi không cần phải khai báo trước — một luồng có thể được đóng bất kỳ lúc nào. Các máy chủ hiện đại tự động chuyển đổi phản hồi chunked HTTP/1.1 thành truyền streaming tương đương khi proxy đến upstream HTTP/2. Chunked Transfer vẫn phù hợp cho các kết nối HTTP/1.1.

Cách thức truyền theo khối hoạt động

Khi máy chủ quyết định sử dụng Chunked Transfer, nó không tính Content-Length mà gửi tiêu đề Transfer-Encoding: chunked. Phần thân phản hồi sau đó được hình thành như một chuỗi các khối. Mỗi khối bắt đầu bằng một dòng chứa kích thước khối ở định dạng thập lục phân (không có tiền tố 0x), theo sau là CRLF ( ). Tiếp theo là dữ liệu khối có kích thước đã chỉ định, kết thúc bằng CRLF. Khối cuối cùng có kích thước 0, sau đó có thể có các tiêu đề trailer.

Kích thước thập lục phân cho phép truyền các khối ở mọi kích thước từ 1 byte đến khối lượng không giới hạn về mặt lý thuyết. Trong thực tế, kích thước khối được máy chủ chọn: các giá trị điển hình là 4 KB, 8 KB hoặc 16 KB. Kích thước khối tối ưu nên là bội số của kích thước phân đoạn TCP (thường là 1460 byte cho Ethernet) để giảm thiểu phân mảnh ở lớp vận chuyển. Nginx sử dụng khối 4 KB theo mặc định, Apache sử dụng khối 8 KB.

Máy khách nhận được Transfer-Encoding: chunked phải đọc phản hồi từng khối một cho đến khối kết thúc có kích thước bằng không. Nếu máy khách không hỗ trợ chunked transfer, máy chủ không thể sử dụng chế độ này. Trong thực tế, tất cả các máy khách HTTP hiện đại — trình duyệt, OkHttp, URLSession, curl — đều hỗ trợ đầy đủ phản hồi chunked. Đọc streaming cho phép máy khách bắt đầu xử lý dữ liệu trước khi nhận được phản hồi đầy đủ, điều này rất quan trọng cho hiệu suất.

Thành phần khốiĐịnh dạngVí dụ
Kích thước khốiHEX + CRLF1000
Dữ liệu khối[kích thước byte] + CRLF[4096 byte dữ liệu]
Khối kết thúc0 0
Trailer (tùy chọn)Tiêu đề + CRLFExpires: Wed, 21 Oct 2025

Tiêu đề Trailer trong Chunked Transfer

Chunked Transfer hỗ trợ tiêu đề trailer — các tiêu đề HTTP bổ sung được truyền sau khối cuối cùng. Điều này hữu ích cho siêu dữ liệu chỉ được biết sau khi hoàn thành việc tạo phản hồi: ví dụ: Content-MD5 hoặc X-Compression-Ratio. Các tiêu đề trailer phải được khai báo trong tiêu đề Trailer: Trailer: Content-MD5, X-Compression-Ratio. Trong thực tế, trailer hiếm khi được sử dụng — hầu hết máy chủ không bao gồm chúng trong phản hồi.

Định dạng phản hồi chunked

Phản hồi chunked có cấu trúc được xác định chặt chẽ mà máy khách phải phân tích chính xác. Hãy xem xét một ví dụ đầy đủ về phản hồi HTTP với Transfer-Encoding: chunked. Sau các tiêu đề và một dòng trống, phần thân phản hồi bắt đầu. Cấu trúc phần thân là một chuỗi: kích_thước_khối dữ_liệu kích_thước_khối dữ_liệu ... cho đến 0 . Mỗi kích thước được truyền bằng ký hiệu thập lục phân sử dụng ký tự ASCII.

Ví dụ phản hồi máy chủ với Chunked Transfer:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

7
Hello
6
World!
0

Trong ví dụ này, máy chủ truyền chuỗi “Hello World!” trong hai khối. Khối đầu tiên có 7 byte chứa “Hello ”, khối thứ hai có 6 byte chứa “World!”. Máy khách thu thập dữ liệu từ cả hai khối và nhận được chuỗi đầy đủ. Quan trọng: kích thước khối chỉ bao gồm dữ liệu, không bao gồm dấu phân cách CRLF của các khối. Khối rỗng kết thúc (0 ) thông báo cho máy khách rằng quá trình truyền đã hoàn tất.

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("Khối: $line")
    }
    reader.close()
}

Phân tích phản hồi chunked trong OkHttp

OkHttp hoàn toàn trừu tượng hóa nhà phát triển khỏi các chi tiết của Chunked Transfer. Khi nhận được phản hồi với Transfer-Encoding: chunked, OkHttp tự động thu thập các khối và cung cấp cho nhà phát triển phần thân phản hồi đầy đủ thông qua response.body?.string(). Để xử lý streaming, response.body?.source() được sử dụng, trả về một BufferedSource và cho phép đọc dữ liệu khi nó đến. Nhà phát triển không cần phải phân tích thủ công kích thước hex và CRLF — thư viện thực hiện việc này tự động.

Chunked Transfer vs Content-Length

Content-Length và Transfer-Encoding: chunked là hai cách loại trừ lẫn nhau để chỉ định kích thước phần thân của thông báo HTTP. Content-Length là một tiêu đề chứa kích thước chính xác của phần thân tính bằng byte. Nó bắt buộc đối với các phản hồi có kích thước được biết trước và cho các yêu cầu có phần thân (POST, PUT). Content-Length cho phép máy khách cấp phát bộ đệm có kích thước cần thiết trước và xác minh rằng tất cả dữ liệu đã được nhận.

Chunked Transfer được sử dụng khi kích thước phần thân không được biết trước. Điều này xảy ra trong ba kịch bản chính: tạo nội dung động (ví dụ: truy vấn cơ sở dữ liệu có kết quả chưa có sẵn), truyền streaming các tệp lớn (để tránh lưu đệm toàn bộ tệp trong bộ nhớ) và Server-Sent Events (SSE) để truyền sự kiện thời gian thực. Sự lựa chọn giữa Content-Length và chunked là trách nhiệm của máy chủ. Nếu máy chủ biết kích thước trước khi bắt đầu truyền, nó nên sử dụng Content-Length như một cơ chế đơn giản hơn và dễ dự đoán hơn.

Đặc tả HTTP/1.1 cấm sử dụng đồng thời Content-Length và Transfer-Encoding: chunked. Nếu máy chủ gửi cả hai tiêu đề, máy khách phải bỏ qua Content-Length và xử lý phản hồi dưới dạng chunked. Ưu tiên của Transfer-Encoding so với Content-Length được thiết lập trong RFC 7230 cho các trường hợp máy chủ proxy sửa đổi phần thân phản hồi và không thể giữ nguyên Content-Length gốc. Một số máy khách HTTP cũ xử lý tình huống này không chính xác, nhưng các triển khai hiện đại tuân theo đặc tả.

Khi nào Content-Length không thể

Có những kịch bản mà Content-Length về cơ bản không thể tính toán trước. Các báo cáo động được tạo theo yêu cầu với bộ lọc và tổng hợp — máy chủ không biết khối lượng dữ liệu cho đến khi truy vấn cơ sở dữ liệu hoàn tất. Video streaming được truyền từ camera theo thời gian thực — kích thước là vô hạn. SSE và long polling cho thông báo — phản hồi có thể kéo dài vô thời hạn. Trong tất cả các trường hợp này, Chunked Transfer là cơ chế chính xác duy nhất.

Streaming dựa trên chunked transfer

Chunked Transfer là nền tảng của nhiều công nghệ streaming trên web. Nổi tiếng nhất là Server-Sent Events (SSE), nơi máy chủ gửi sự kiện đến máy khách qua một kết nối HTTP duy nhất với Transfer-Encoding: chunked. SSE sử dụng định dạng văn bản đặc biệt (data: tin nhắn ), nhưng lớp vận chuyển là chunked transfer thông thường. Trình duyệt nhận sự kiện khi máy chủ gửi chúng, mà không cần đợi phản hồi hoàn tất.

Streaming âm thanh và video cũng dựa trên Chunked Transfer. Các máy chủ phương tiện như Nginx RTMP và Wowza Streaming Engine gửi dữ liệu phương tiện theo khối qua HTTP. Trình phát phía máy khách bắt đầu phát lại ngay khi nhận được khối đầu tiên, mà không cần đợi tệp tải hoàn tất. Điều này giảm thời gian đến khung hình đầu tiên từ hàng chục giây xuống còn 1-2 giây. YouTube và Netflix sử dụng chính xác cách tiếp cận này cho các luồng HTTP của họ.

Trong phát triển di động, Chunked Transfer được sử dụng để truyền khối lượng lớn dữ liệu mà không tải toàn bộ phản hồi vào bộ nhớ. Khi tải hình ảnh qua Coil hoặc Glide trên Android, các thư viện đọc dữ liệu streaming theo từng khối và giải mã dần hình ảnh. Điều này cho phép hiển thị hình ảnh lớn (10+ MB) mà không gặp OutOfMemoryError. OkHttp hỗ trợ đọc streaming qua response.body?.byteStream(), trả về InputStream đọc dữ liệu từng khối một.

Chunked transfer trong gRPC và GraphQL

gRPC sử dụng HTTP/2, nơi streaming được tích hợp ở cấp giao thức và không yêu cầu cơ chế chunked riêng biệt. Các máy chủ GraphQL chạy qua HTTP/1.1 có thể sử dụng Chunked Transfer để truyền streaming kết quả đăng ký. Apollo Server và Hasura gửi phản hồi chunked cho các đăng ký GraphQL, truyền sự kiện khi chúng xảy ra. Máy khách nhận được cập nhật thời gian thực mà không cần thăm dò.

Ưu điểm và hạn chế

Chunked Transfer cung cấp những lợi ích quan trọng cho ứng dụng web. Gửi dữ liệu tức thời — máy chủ không lưu đệm phản hồi trước khi gửi, giảm độ trễ đến byte đầu tiên. Xử lý streaming — máy khách có thể bắt đầu xử lý dữ liệu khi nó đến mà không cần đợi tải xuống hoàn tất. Không có giới hạn bộ nhớ — máy chủ không lưu trữ toàn bộ phản hồi trong bộ nhớ, điều này rất quan trọng cho khối lượng dữ liệu lớn. Khả năng truyền các luồng vô hạn — SSE, video trực tiếp, giám sát.

Tuy nhiên, Chunked Transfer có những hạn chế. Chi phí cho mỗi khối là 6-12 byte cho kích thước + CRLF, và đối với nhiều khối nhỏ (ví dụ: 100 byte mỗi khối) có thể tăng kích thước phản hồi lên 10-15%. Không thể chỉ định kích thước chính xác — máy khách không thể cấp phát bộ đệm trước hoặc hiển thị thanh tiến trình. Vấn đề với máy chủ proxy — một số proxy cũ không hỗ trợ chunked transfer và không thể lưu trữ các phản hồi đó. Không hỗ trợ tiếp tục tải xuống — không thể thực hiện yêu cầu Range cho các phản hồi chunked đã nhận một phần.

Theo HTTP Archive, 2025, khoảng 35% tất cả các phản hồi HTTP sử dụng Transfer-Encoding: chunked. Trong số đó, các trang động chiếm ưu thế (60%), tiếp theo là phản hồi API (25%) và luồng phương tiện (15%). Các tệp tĩnh hầu như luôn sử dụng Content-Length vì kích thước của chúng được biết trước. Tỷ lệ phản hồi chunked đang giảm dần cùng với việc áp dụng HTTP/2, nơi streaming được triển khai ở cấp khung mà không cần tiêu đề Transfer-Encoding bổ sung.

Khuyến nghị thực tế

Trong phát triển di động, hãy sử dụng Chunked Transfer để tải xuống các tệp lớn (hình ảnh, video) và cho các yêu cầu API trả về mảng dữ liệu lớn. OkHttp hỗ trợ đầy đủ chunked transfer mà không cần cấu hình bổ sung. Đối với tải lên máy chủ, Chunked Transfer không được sử dụng — HTTP/1.1 không có Transfer-Encoding cho tải lên. Trên iOS, URLSession hỗ trợ cả việc gửi và nhận dữ liệu chunked mà không cần cấu hình đặc biệt. Phân tích JSON streaming (ví dụ: qua Jackson Streaming API hoặc Moshi) cho phép xử lý các mảng JSON lớn khi chúng đến trong một luồng chunked.

Các câu hỏi thường gặp

Làm thế nào máy chủ bật Chunked Transfer?

Máy chủ bật Chunked Transfer tự động khi kích thước phản hồi không xác định. Nginx thêm Transfer-Encoding: chunked nếu Content-Length không được đặt. Trong Spring Boot, StreamingResponseBody và SseEmitter tự động sử dụng chunked transfer. Trong Node.js Express, phản hồi trở thành chunked nếu gọi res.write() và res.end() mà không có Content-Length.

Có thể sử dụng Content-Length và chunked đồng thời không?

Không, đặc tả HTTP/1.1 cấm sử dụng đồng thời Content-Length và Transfer-Encoding: chunked. Nếu máy chủ gửi cả hai tiêu đề, máy khách phải bỏ qua Content-Length và xử lý phản hồi dưới dạng chunked. Quy tắc này được thiết lập trong RFC 7230 để tương thích với các máy chủ proxy có thể sửa đổi phần thân phản hồi.

Kích thước khối tối ưu là bao nhiêu?

Kích thước khối tối ưu phụ thuộc vào kịch bản. Đối với các trang web thông thường — 4-8 KB. Đối với streaming video — 16-64 KB. Đối với SSE — khối tối thiểu 1-2 KB để giảm độ trễ. Kích thước khối nên là bội số của kích thước phân đoạn TCP (1460 byte cho Ethernet) để giảm thiểu phân mảnh ở lớp vận chuyển.

Chunked Transfer có hoạt động qua proxy không?

Các máy chủ proxy hiện đại (Nginx, HAProxy, Envoy) hỗ trợ Chunked Transfer. Proxy có thể chuyển tiếp các khối mà không lưu đệm (streaming) hoặc lưu đệm toàn bộ phản hồi và gửi lại với Content-Length. Các proxy cũ có thể lưu đệm phản hồi chunked cho đến khi hoàn tất, làm tăng độ trễ. HTTP/2 giải quyết vấn đề này ở cấp giao thức.

Chunked Transfer khác HTTP chunked encoding như thế nào?

Chúng là một. Chunked Transfer là tên đầy đủ của cơ chế từ đặc tả HTTP/1.1. HTTP chunked encoding cũng giống vậy, đôi khi được sử dụng trong tài liệu thư viện. Transfer-Encoding: chunked là tiêu đề bật chế độ này. Cả ba thuật ngữ mô tả cùng một cơ chế truyền dữ liệu thành nhiều phần.

Tóm tắt

  • Chunked Transfer — cơ chế HTTP/1.1 truyền phần thân phản hồi theo khối mà không chỉ định trước Content-Length.
  • Transfer-Encoding: chunked — tiêu đề bật truyền theo khối; mỗi khối chứa kích thước hex, dữ liệu và CRLF.
  • Khối kết thúc có kích thước bằng không báo hiệu kết thúc truyền, sau đó có thể có tiêu đề trailer.
  • Streaming nội dung động — trường hợp sử dụng chính: trang động, SSE, âm thanh/video streaming, báo cáo dài.
  • Content-Length và chunked loại trừ lẫn nhau — đặc tả cấm sử dụng đồng thời các tiêu đề này.
  • Ưu điểm — giảm độ trễ, tiết kiệm bộ nhớ, khả năng truyền luồng vô hạn và xử lý streaming ở phía máy khách.
  • Hạn chế — chi phí tiêu đề khối, không thể hiển thị tiến trình, vấn đề với máy chủ proxy cũ.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm