Multipart Upload adalah mekanisme HTTP yang memungkinkan transmisi beberapa bagian data yang heterogen dalam satu permintaan, termasuk bidang teks dan file biner. Setiap bagian dipisahkan oleh string batas unik dan memiliki header Content-Type sendiri. Menurut MDN Web Docs, 2025, multipart/form-data adalah format standar untuk mengunggah file melalui formulir HTML dan banyak digunakan dalam aplikasi web dan seluler untuk mengirim gambar, dokumen, dan file lainnya ke server.
Poin Penting
Multipart Upload adalah metode transmisi data melalui protokol HTTP, di mana badan permintaan terdiri dari beberapa bagian yang dipisahkan secara logis. Setiap bagian dapat berisi data dengan tipe berbeda: bidang teks formulir, file biner, objek JSON, atau gambar. Semua bagian dikemas dalam satu permintaan POST, yang menghilangkan kebutuhan untuk mengirim N panggilan HTTP terpisah. Multipart Upload adalah bagian integral dari formulir web dan API untuk mengunggah file.
Format multipart didefinisikan dalam spesifikasi RFC 2046 sebagai bagian dari standar MIME untuk pesan email, kemudian diadaptasi untuk HTTP dalam RFC 1867. Saat ini dalam pengembangan web hampir secara eksklusif menggunakan multipart/form-data — salah satu subtipe multipart, yang ditujukan untuk formulir yang berisi file. Subtipe lainnya — multipart/mixed (untuk lampiran arbitrer) dan multipart/byteranges (untuk unduhan file parsial) — jauh lebih jarang digunakan.
Perbedaan mendasar antara multipart dan application/x-www-form-urlencoded sederhana adalah bahwa yang terakhir mengenkripsi semua data menjadi string yang kompatibel dengan URI dan tidak mendukung file biner. Multipart/form-data, sebaliknya, mentransmisikan setiap file dalam bentuk biner aslinya tanpa pengkodean, yang lebih efisien dan tidak kehilangan presisi. Ukuran permintaan pada multipart hanya 5-15% lebih besar dari jumlah ukuran file karena overhead header bagian dan batas.
Multipart Upload digunakan di mana pun diperlukan unggahan file: avatar dan foto profil di media sosial, lampiran di aplikasi pesan, dokumen di sistem CRM, gambar produk di toko online. Dalam aplikasi seluler, Multipart Upload digunakan untuk mengirim konten media ke server — foto dari kamera perangkat, rekaman suara, fragmen video. Menurut data Cloudflare Research, sekitar 15% dari semua permintaan POST di web menggunakan multipart/form-data.
Multipart Upload dan Chunked Transfer adalah mekanisme yang berbeda. Multipart membagi permintaan menjadi bagian-bagian yang bermakna (bidang dan file), sementara Chunked Transfer membagi aliran data menjadi fragmen-fragmen untuk transmisi tanpa mengetahui ukuran total. Multipart dapat ditransmisikan di dalam Chunked Transfer: server mengirimkan respons multipart dalam bagian-bagian, tanpa mengetahui volume totalnya. Mekanisme ini tidak bertentangan dan menyelesaikan tugas yang berbeda pada level yang berbeda.
Ketika browser mengirimkan formulir dengan atribut enctype="multipart/form-data", ia membangun badan permintaan dalam format multipart. Setiap bidang formulir menjadi blok terpisah, dipisahkan dari yang lain oleh string batas (boundary). Batas dihasilkan secara otomatis dan merupakan urutan karakter unik yang dijamin tidak ditemukan di dalam data. Klien menambahkan batas ini ke header Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryX7K.
Setiap blok dimulai dengan --boundary dan berisi header Content-Disposition dengan nama bidang (name) dan, untuk file, nama file asli (filename). Setelah baris kosong, langsung menyusul data bidang atau konten file dalam bentuk biner. Permintaan diakhiri dengan string --boundary--. Server mengurai aliran yang diterima: pertama menemukan batas, kemudian mengekstrak header setiap bagian, menentukan tipe data, dan meneruskannya ke penangan formulir atau pengontrol API.
Menurut IETF RFC 7578, multipart/form-data tidak memerlukan penentuan charset untuk setiap bagian, karena bidang teks dianggap UTF-8, dan bagian biner berisi file dalam pengkodean aslinya. Ukuran satu bagian tidak dibatasi oleh protokol — batasan dikonfigurasi di level server: misalnya, di Nginx melalui client_max_body_size, di Spring Boot melalui spring.servlet.multipart.max-file-size.
Boundary adalah string unik yang tidak boleh muncul dalam data yang ditransmisikan. Biasanya dimulai dengan awalan (misalnya, ----WebKitFormBoundary atau ----Boundary) dan berisi karakter acak. Browser dan klien HTTP menghasilkan boundary secara otomatis. Panjang boundary tidak boleh melebihi 70 karakter menurut RFC 2046. Setiap bagian dipisahkan oleh string --boundary\r\n, dan akhir permintaan oleh --boundary--\r\n.
Permintaan multipart memiliki struktur ketat yang ditentukan oleh standar MIME dan HTTP. Header permintaan menetapkan Content-Type: multipart/form-data dengan parameter boundary. Badan permintaan terdiri dari urutan bagian, yang masing-masing berisi header dan badan sendiri. Header bagian mencakup Content-Disposition (wajib) dan Content-Type (opsional — untuk file). Keberadaan baris kosong antara header bagian dan datanya adalah wajib.
| Elemen | Contoh | Keharusan |
|---|---|---|
| Content-Type | multipart/form-data; boundary=---Bnd123 | Ya |
| Pemisah bagian | ---Bnd123 | Ya (sebelum setiap bagian) |
| Content-Disposition | form-data; name="avatar"; filename="photo.jpg" | Ya |
| Content-Type bagian | image/jpeg | Untuk file |
| Badan bagian | [data biner gambar] | Ya |
| Batas akhir | ---Bnd123-- | Ya (akhir permintaan) |
Mari kita lihat contoh nyata permintaan multipart yang mengirim bidang teks dan file gambar. Klien membentuk header Content-Type dengan boundary unik. Badan permintaan secara berurutan berisi semua bidang formulir. Server saat menerima mengurai bagian-bagian ini dan memberikan pengembang akses ke setiap bidang sebagai objek terpisah. Pendekatan ini memungkinkan pemrosesan formulir kompleks dengan file dalam satu panggilan HTTP.
import okhttp3.*
import java.io.File
fun uploadFile() {
val client = OkHttpClient()
val imageFile = File("/path/to/photo.jpg")
val requestBody = MultipartBody.Builder()
.setType(MediaType.parse("multipart/form-data"))
.addFormDataPart("username", "john_doe")
.addFormDataPart(
"avatar", "photo.jpg",
RequestBody.create(
MediaType.parse("image/jpeg"), imageFile
)
)
.build()
val request = Request.Builder()
.url("https://api.example.com/upload")
.post(requestBody)
.build()
client.newCall(request).execute().use { response ->
println("Diunggah: ${response.isSuccessful}")
}
}
Di sisi server, permintaan multipart diurai oleh framework atau secara manual. Di Spring Boot, cukup dengan anotasi @RequestParam("avatar") MultipartFile file, dan framework secara otomatis mengekstrak file dari permintaan multipart. Di Ktor pada Kotlin, digunakan receiveMultipart(), di Express.js — middleware multer. Server mendapatkan akses ke setiap bidang formulir dan setiap file yang diunggah secara independen, menyimpan file di disk atau penyimpanan cloud, dan mengembalikan URL atau pengidentifikasi ke klien.
Multipart Upload memberikan beberapa keunggulan utama dibandingkan metode transmisi data alternatif. Satu permintaan, bukan banyak — semua bidang formulir dan file ditransmisikan dalam satu panggilan HTTP, yang mengurangi beban jaringan dan server. Tidak perlu membuka N koneksi untuk mengunggah N file — semuanya dikemas dalam satu POST. Ini sangat penting untuk aplikasi seluler, di mana setiap koneksi HTTP berarti latensi dan konsumsi baterai.
Transmisi biner tanpa pengkodean — tidak seperti application/x-www-form-urlencoded, di mana data biner dikodekan dalam base64 (peningkatan ukuran 33%), multipart/form-data mentransmisikan file dalam bentuk biner asli. Ini lebih efisien dalam hal ukuran dan kecepatan. Untuk file besar dari 10 MB ke atas, perbedaannya menjadi kritis: permintaan multipart akan 30% lebih kecil daripada permintaan URL-encoded dengan file yang sama.
Struktur arbitrer — multipart memungkinkan penggabungan bidang dari berbagai jenis dalam urutan apa pun. Formulir dapat berisi bidang teks, beberapa file, data JSON, dan bidang tersembunyi secara bersamaan. Setiap bagian memiliki Content-Type sendiri, yang memungkinkan pencampuran data teks dan biner. Sebagai perbandingan: pengkodean base64 menambah 33% pada ukuran, sementara multipart hanya sekitar 5-15% untuk header layanan.
Menurut studi HTTP Archive, 2025, multipart/form-data digunakan dalam 94% kasus unggahan file di web. Alternatif — base64 dalam JSON (4%) dan transmisi langsung melalui WebSocket (2%). JSON dengan base64 nyaman untuk API di mana semua data lain juga dalam JSON, tetapi tidak efisien untuk file besar. WebSocket cocok untuk real-time, tetapi tidak didukung oleh semua infrastruktur HTTP. Multipart tetap menjadi standar untuk unggahan file berkat kesederhanaan dan efisiensinya.
Dalam aplikasi seluler, Multipart Upload digunakan untuk mengirim konten media dari perangkat pengguna: foto dari galeri, gambar dari kamera, rekaman suara, file dokumen. Di Android, cara standar adalah OkHttp dengan MultipartBody.Builder, yang memungkinkan pembentukan permintaan multipart dengan mudah. Retrofit juga mendukung multipart melalui anotasi @Multipart dan @Part. Pengembang menentukan tipe data untuk setiap bagian, klien HTTP secara otomatis menghasilkan header yang benar.
Di iOS, tugas yang sama diselesaikan melalui URLSession dengan HTTPBodyStream kustom atau melalui Alamofire dengan multipartFormData. Alamofire menyediakan metode praktis upload(multipartFormData:) untuk mengirim permintaan multipart. Di kedua platform, penting untuk mempertimbangkan ukuran file yang diunggah — untuk file besar (lebih dari 10-20 MB), disarankan menggunakan unggahan latar belakang agar aplikasi tidak tertutup saat diminimalkan. Di Android, untuk ini digunakan DownloadManager atau WorkManager, di iOS — URLSession dengan konfigurasi background.
Saat mengunggah file dalam aplikasi seluler, perlu mempertimbangkan status jaringan. Connectivity Manager di Android membantu menentukan apakah Wi-Fi atau data seluler tersedia dan memilih momen optimal untuk unggahan. Untuk file besar seperti video, disarankan menunda unggahan sampai terhubung ke Wi-Fi, agar tidak menghabiskan lalu lintas seluler pengguna. WorkManager di Android memungkinkan mengonfigurasi batasan tersebut melalui NetworkType.UNMETERED.
Sebelum mengirim file melalui Multipart Upload, aplikasi seluler sering mengompres dan mengubah ukuran gambar. Kompresi JPEG dengan kualitas 85% mengurangi ukuran file 3-5 kali tanpa kehilangan kualitas yang terlihat untuk tampilan di layar. Mengubah ukuran gambar menjadi 1920px pada sisi yang lebih panjang semakin mengurangi ukuran. Di Android, untuk ini digunakan Bitmap.compress(), di iOS — UIImageJPEGRepresentation dengan parameter kompresi 0.85. Optimasi semacam itu mempercepat unggahan dan menghemat lalu lintas seluler.
Kesalahan paling umum pada Multipart Upload — melebihi batas ukuran permintaan di server. Secara default, Nginx membatasi ukuran badan permintaan hingga 1 MB (client_max_body_size), dan Tomcat hingga 2 MB (maxSwallowSize). Jika pengembang tidak meningkatkan batas ini, server akan mengembalikan kesalahan 413 Request Entity Too Large. Solusinya — secara eksplisit mengonfigurasi ukuran unggahan maksimum di server dan menampilkan peringatan di klien jika file melebihi ukuran yang diizinkan.
Masalah kedua — pemrosesan permintaan multipart yang tidak benar saat melakukan streaming badan. Beberapa server mencoba memuat seluruh permintaan multipart ke memori sebelum penguraian, yang menyebabkan OutOfMemoryError untuk file besar. Server modern (Nginx, Spring Boot, Ktor) mendukung penguraian streaming multipart, di mana setiap bagian diproses saat tiba. Pengembang harus memastikan server dikonfigurasi untuk pemrosesan streaming permintaan multipart.
Kategori masalah ketiga — timeout saat mengunggah file besar. Klien HTTP memiliki pengaturan readTimeout dan connectTimeout yang dapat teraktivasi saat unggahan berkepanjangan file lebih dari 50-100 MB. Solusinya — tingkatkan timeout untuk endpoint unggahan atau gunakan chunked transfer encoding di dalam multipart. Di perangkat seluler, juga penting untuk menangani interupsi unggahan dan mengimplementasikan kelanjutan (resume) jika koneksi terputus.
Unggahan file melalui multipart adalah salah satu endpoint paling rentan dari aplikasi web. Penyerang dapat mengunggah skrip yang dapat dieksekusi dengan mengganti namanya menjadi image.jpg. Server harus memeriksa tipe MIME file yang diunggah bukan berdasarkan ekstensi, tetapi berdasarkan konten (magic bytes), membatasi tipe yang diizinkan, dan memindai file dengan antivirus. Disarankan untuk menyimpan file yang diunggah di luar document-root server web dan menyajikannya melalui pengontrol terpisah dengan pemeriksaan hak akses.
Pertanyaan Umum
multipart/form-data mentransmisikan setiap bidang formulir sebagai blok terpisah dengan headernya sendiri dan mendukung file biner tanpa pengkodean. application/x-www-form-urlencoded mengkodekan semua data menjadi string yang kompatibel dengan URI (kunci=nilai&kunci2=nilai2) dan tidak mendukung file secara langsung — file harus dikodekan dalam base64.
Protokol HTTP tidak membatasi ukuran permintaan multipart, tetapi dalam praktiknya batasan ditetapkan oleh server. Nginx secara default membatasi hingga 1 MB, Apache — hingga 2 MB, Spring Boot — hingga 1 MB. Untuk mengunggah file besar, konfigurasikan client_max_body_size (Nginx) atau spring.servlet.multipart.max-file-size (Spring Boot) ke nilai yang diinginkan — misalnya, 100 MB.
Ya, multipart/form-data mendukung banyak file dalam satu permintaan. Setiap file ditransmisikan sebagai bagian terpisah dengan Content-Disposition dan Content-Type sendiri. Formulir HTML menggunakan atribut multiple untuk input type="file". Di OkHttp, untuk ini dipanggil addFormDataPart untuk setiap file, di Alamofire — append untuk setiap file.
Boundary adalah string unik yang memisahkan bagian-bagian permintaan majemuk dan memungkinkan server menentukan di mana satu bagian berakhir dan bagian lain dimulai. Ini dihasilkan oleh klien dan ditentukan dalam header Content-Type. Tanpa boundary, server tidak dapat memisahkan permintaan multikomponen menjadi bidang dan file individual.
Jangan mengandalkan ekstensi file atau Content-Type dari permintaan — penyerang dapat memalsukannya. Periksa tipe MIME melalui magic bytes (byte pertama file): pustaka Apache Tika di Java, libmagic di C/C++, perintah file di Linux, atau alat bawaan framework — Files.probeContentType() di Java, mimetypes di Python.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga