Chunked Transfer เป็นกลไกของโปรโตคอล HTTP ที่เซิร์ฟเวอร์ส่งเนื้อหาของการตอบกลับเป็นส่วนแยกกัน (chunks) โดยไม่ระบุขนาดรวมของข้อมูลล่วงหน้า แต่ละ chunk มีขนาดในรูปแบบเลขฐานสิบหกและข้อมูลตามความยาวที่กำหนด และจบลงด้วย chunk สุดท้ายที่มีขนาดเป็นศูนย์ ตามข้อมูลจาก MDN Web Docs, 2025 Transfer-Encoding: chunked จะถูกเปิดใช้งานโดยอัตโนมัติเมื่อเซิร์ฟเวอร์ไม่ทราบขนาดการตอบกลับล่วงหน้า — ตัวอย่างเช่น ระหว่างการสร้างเนื้อหาแบบทันทีหรือการส่งข้อมูลแบบสตรีมมิ่ง
ประเด็นสำคัญ
Chunked Transfer เป็นกลไก HTTP ที่กำหนดในข้อกำหนด HTTP/1.1 (RFC 7230 ส่วนที่ 4.1) ซึ่งอนุญาตให้เซิร์ฟเวอร์ส่งเนื้อหาของการตอบกลับเป็นส่วนโดยไม่ต้องระบุ Content-Length ทั้งหมด แทนที่จะคำนวณขนาดการตอบกลับก่อนส่ง เซิร์ฟเวอร์จะเริ่มส่งข้อมูลทันที โดยส่งส่วนของข้อมูลเมื่อพร้อม แต่ละส่วนมาพร้อมกับส่วนหัวขนาดของตัวเอง ทำให้ไคลเอนต์สามารถประกอบการตอบกลับจากส่วนต่างๆ ได้
กลไกนี้เปิดใช้งานโดยส่วนหัว Transfer-Encoding: chunked เมื่อไคลเอนต์เห็นส่วนหัวนี้ในการตอบกลับ มันจะรู้ว่าเนื้อหาจะถูกส่งเป็น chunk และต้องอ่านการตอบกลับในลูป: อ่านขนาดของ chunk จากนั้นอ่านข้อมูลตามขนาดที่ระบุ จากนั้นทำซ้ำ กระบวนการจะสิ้นสุดลงเมื่อพบ chunk ที่มีขนาดเป็นศูนย์ 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 จากนั้นเนื้อหาการตอบกลับจะถูกสร้างเป็นลำดับของ chunk แต่ละ chunk เริ่มต้นด้วยบรรทัดที่มีขนาดของ chunk ในรูปแบบเลขฐานสิบหก (โดยไม่มีคำนำหน้า 0x) ตามด้วย CRLF ( ) จากนั้นมาข้อมูลของ chunk ตามขนาดที่ระบุ ซึ่งลงท้ายด้วย CRLF chunk สุดท้ายมีขนาด 0 หลังจากนั้นอาจมีส่วนหัว trailer
ขนาดเลขฐานสิบหกอนุญาตให้ส่ง chunk ทุกขนาดตั้งแต่ 1 ไบต์ไปจนถึงปริมาณที่ไม่จำกัดในทางทฤษฎี ในทางปฏิบัติ ขนาดของ chunk จะถูกเลือกโดยเซิร์ฟเวอร์: ค่าทั่วไปคือ 4 KB, 8 KB หรือ 16 KB ขนาด chunk ที่เหมาะสมที่สุดควรเป็นตัวคูณของขนาดเซกเมนต์ TCP (โดยปกติ 1460 ไบต์สำหรับอีเทอร์เน็ต) เพื่อลดการแยกส่วนในระดับการขนส่ง Nginx ใช้ chunk ขนาด 4 KB เป็นค่าเริ่มต้น Apache ใช้ chunk ขนาด 8 KB
ไคลเอนต์ที่ได้รับ Transfer-Encoding: chunked ต้องอ่านการตอบกลับทีละ chunk จนถึง chunk ศูนย์สุดท้าย หากไคลเอนต์ไม่รองรับ chunked transfer เซิร์ฟเวอร์จะไม่สามารถใช้โหมดนี้ได้ ในทางปฏิบัติ ไคลเอนต์ HTTP ที่ทันสมัยทั้งหมด — เบราว์เซอร์, OkHttp, URLSession, curl — รองรับการตอบกลับแบบ chunked อย่างสมบูรณ์ การอ่านแบบสตรีมมิ่ง ช่วยให้ไคลเอนต์เริ่มประมวลผลข้อมูลก่อนที่จะได้รับการตอบกลับทั้งหมด ซึ่งสำคัญต่อประสิทธิภาพ
| องค์ประกอบของ chunk | รูปแบบ | ตัวอย่าง |
|---|---|---|
| ขนาดของ chunk | HEX + CRLF | 1000 |
| ข้อมูลของ chunk | [ขนาดไบต์] + CRLF | [4096 ไบต์ข้อมูล] |
| chunk สุดท้าย | 0 | 0 |
| Trailer (ตัวเลือก) | ส่วนหัว + CRLF | Expires: Wed, 21 Oct 2025 |
Chunked Transfer รองรับส่วนหัว trailer — ส่วนหัว HTTP เพิ่มเติมที่ส่งหลังจาก chunk สุดท้าย ซึ่งมีประโยชน์สำหรับข้อมูลเมตาที่ทราบหลังจากสร้างการตอบกลับเสร็จสมบูรณ์แล้วเท่านั้น: ตัวอย่างเช่น Content-MD5 หรือ X-Compression-Ratio ส่วนหัว trailer ต้องประกาศในส่วนหัว Trailer: Trailer: Content-MD5, X-Compression-Ratio ในทางปฏิบัติ trailer ไม่ค่อยถูกใช้ — เซิร์ฟเวอร์ส่วนใหญ่ไม่รวมไว้ในการตอบกลับ
การตอบกลับแบบ chunked มีโครงสร้างที่กำหนดไว้อย่างเคร่งครัดซึ่งไคลเอนต์ต้องแยกวิเคราะห์อย่างถูกต้อง มาดูตัวอย่างเต็มรูปแบบของการตอบกลับ HTTP ที่มี Transfer-Encoding: chunked หลังจากส่วนหัวและบรรทัดว่าง เนื้อหาการตอบกลับเริ่มต้นขึ้น โครงสร้างของเนื้อหาเป็นลำดับ: ขนาด_chunk ข้อมูล ขนาด_chunk ข้อมูล ... ถึง 0 แต่ละขนาดถูกส่งในรูปแบบเลขฐานสิบหกโดยใช้อักขระ ASCII
ตัวอย่างการตอบกลับของเซิร์ฟเวอร์ด้วย Chunked Transfer:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
7
Hello
6
World!
0
ในตัวอย่างนี้ เซิร์ฟเวอร์ส่งสตริง “Hello World!” ในสอง chunk chunk แรกมี 7 ไบต์ประกอบด้วย “Hello ” chunk ที่สองมี 6 ไบต์ประกอบด้วย “World!” ไคลเอนต์รวบรวมข้อมูลจากทั้งสอง chunk และรับสตริงที่สมบูรณ์ สำคัญ: ขนาดของ chunk รวมเฉพาะข้อมูล ไม่รวมตัวคั่น CRLF ของ chunk เอง chunk ว่างสุดท้าย (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 จะรวบรวม chunk โดยอัตโนมัติและให้นักพัฒนาได้รับเนื้อหาการตอบกลับทั้งหมดผ่าน response.body?.string() สำหรับการประมวลผลแบบสตรีมมิ่ง ใช้ response.body?.source() ซึ่งส่งคืน BufferedSource และอนุญาตให้อ่านข้อมูลเมื่อมาถึง นักพัฒนาไม่จำเป็นต้องแยกวิเคราะห์ขนาดเลขฐานสิบหกและ 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 ส่งข้อมูลมีเดียเป็น chunk ผ่าน HTTP เครื่องเล่นฝั่งไคลเอนต์เริ่มเล่นทันทีที่ได้รับ chunk แรก โดยไม่ต้องรอให้ไฟล์โหลดทั้งหมด ซึ่งลดเวลาจนถึงเฟรมแรกจากหลายสิบวินาทีเหลือ 1-2 วินาที YouTube และ Netflix ใช้วิธีนี้สำหรับสตรีม HTTP ของพวกเขา
ในการพัฒนามือถือ Chunked Transfer ใช้สำหรับส่งข้อมูลปริมาณมากโดยไม่ต้องโหลดการตอบกลับทั้งหมดในหน่วยความจำ เมื่อโหลดรูปภาพผ่าน Coil หรือ Glide บน Android ไลบรารีจะอ่านข้อมูลสตรีมมิ่งทีละ chunk และถอดรหัสรูปภาพทีละน้อย ซึ่งช่วยให้แสดงรูปภาพขนาดใหญ่ (10+ MB) โดยไม่มี OutOfMemoryError OkHttp รองรับการอ่านแบบสตรีมมิ่งผ่าน response.body?.byteStream() ซึ่งส่งคืน InputStream ที่อ่านข้อมูลทีละ chunk
gRPC ใช้ HTTP/2 ซึ่งสตรีมมิ่งถูกสร้างไว้ในระดับโปรโตคอลและไม่ต้องการกลไก chunked แยกต่างหาก เซิร์ฟเวอร์ GraphQL ที่ทำงานผ่าน HTTP/1.1 สามารถใช้ Chunked Transfer สำหรับการสตรีมผลลัพธ์ของการสมัครรับข้อมูล Apollo Server และ Hasura ส่งการตอบกลับแบบ chunked สำหรับการสมัครรับข้อมูล GraphQL โดยส่งเหตุการณ์เมื่อเกิดขึ้น ไคลเอนต์ได้รับการอัปเดตแบบเรียลไทม์โดยไม่ต้องใช้การสอบถาม
Chunked Transfer ให้ข้อดีที่สำคัญสำหรับแอปพลิเคชันเว็บ การส่งข้อมูลทันที — เซิร์ฟเวอร์ไม่บัฟเฟอร์การตอบกลับก่อนส่ง ลดระยะเวลารอคอยจนถึงไบต์แรก การประมวลผลแบบสตรีมมิ่ง — ไคลเอนต์สามารถเริ่มประมวลผลข้อมูลเมื่อมาถึงโดยไม่ต้องรอการดาวน์โหลดทั้งหมด ไม่มีข้อจำกัดด้านหน่วยความจำ — เซิร์ฟเวอร์ไม่ได้เก็บการตอบกลับทั้งหมดในหน่วยความจำ ซึ่งสำคัญสำหรับปริมาณข้อมูลขนาดใหญ่ ความสามารถในการส่งสตรีมไม่จำกัด — SSE, วีดีโอสด, การตรวจสอบ
อย่างไรก็ตาม Chunked Transfer มีข้อจำกัด ค่าใช้จ่ายเพิ่มเติมสำหรับแต่ละ chunk คือ 6-12 ไบต์สำหรับขนาด + CRLF ซึ่งสำหรับ chunk ขนาดเล็กจำนวนมาก (เช่น 100 ไบต์แต่ละอัน) อาจเพิ่มขนาดการตอบกลับขึ้น 10-15% ไม่สามารถระบุขนาดที่แน่นอนได้ — ไคลเอนต์ไม่สามารถจัดสรรบัฟเฟอร์ล่วงหน้าหรือแสดงแถบความคืบหน้า ปัญหากับเซิร์ฟเวอร์พร็อกซี — พร็อกซีรุ่นเก่าบางตัวไม่รองรับ chunked transfer และไม่สามารถแคชการตอบกลับดังกล่าว ไม่รองรับการดาวน์โหลดต่อ — ไม่สามารถทำคำขอ Range สำหรับการตอบกลับแบบ chunked ที่ได้รับบางส่วน
ตามข้อมูลของ 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 อย่างสมบูรณ์โดยไม่ต้องกำหนดค่าเพิ่มเติม สำหรับ การอัปโหลดไปยังเซิร์ฟเวอร์ Chunked Transfer ไม่ได้ใช้ — HTTP/1.1 ไม่มี Transfer-Encoding สำหรับการอัปโหลด บน 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 เพื่อความเข้ากันได้กับเซิร์ฟเวอร์พร็อกซีที่อาจแก้ไขเนื้อหาการตอบกลับ
ขนาด chunk ที่เหมาะสมขึ้นอยู่กับสถานการณ์ สำหรับหน้าเว็บทั่วไป — 4-8 KB สำหรับสตรีมมิ่งวีดีโอ — 16-64 KB สำหรับ SSE — chunk ขนาดเล็ก 1-2 KB เพื่อลดระยะเวลารอคอย ขนาดของ chunk ควรเป็นตัวคูณของขนาดเซกเมนต์ TCP (1460 ไบต์สำหรับอีเทอร์เน็ต) เพื่อลดการแยกส่วนในระดับการขนส่ง
เซิร์ฟเวอร์พร็อกซีสมัยใหม่ (Nginx, HAProxy, Envoy) รองรับ Chunked Transfer พร็อกซีสามารถส่งต่อ chunk โดยไม่ต้องบัฟเฟอร์ (สตรีมมิ่ง) หรือบัฟเฟอร์การตอบกลับทั้งหมดแล้วส่งใหม่ด้วย Content-Length พร็อกซีรุ่นเก่า อาจบัฟเฟอร์การตอบกลับแบบ chunked จนเสร็จสมบูรณ์ ซึ่งเพิ่มระยะเวลารอคอย HTTP/2 แก้ปัญหานี้ในระดับโปรโตคอล
มันเป็นสิ่งเดียวกัน Chunked Transfer คือชื่อเต็มของกลไกจากข้อกำหนด HTTP/1.1 HTTP chunked encoding ก็เหมือนกัน บางครั้งใช้ในเอกสารของไลบรารี Transfer-Encoding: chunked คือส่วนหัวที่เปิดใช้งานโหมดนี้ ทั้งสามคำอธิบายถึงกลไกเดียวกันในการส่งข้อมูลเป็นส่วน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม