Alat pengembang · Encoder & decoder Base64
Base64 di JSON API: mengapa bidang biner dikodekan dan berapa biayanya
· Mengapa itu penting
base64 pengkodean
JSON tidak memiliki tipe byte, jadi data biner biasanya dikodekan Base64 menjadi string. Posting ini menjelaskan mengapa konvensi itu ada, berapa biayanya dalam ukuran dan CPU, dan kapan titik akhir biner terpisah adalah pilihan yang lebih baik.
Bidang PDF yang mendominasi respons — muatan API yang konkret di mana satu blob Base64 melebihi yang lainnya
Respons API berisi objek besar dengan satu bidang yang mendominasi ukuran payload. Responsnya adalah JSON, jadi setiap nilai adalah string atau angka. Sebagian besar kolom berukuran kecil: ID pengguna, stempel waktu, kode status. Satu bidang berisi imageData atau fileContents dan merupakan string Base64 40-kilobyte. Keseluruhan responsnya adalah 50 kilobyte. Bidang tunggal tersebut menyumbang 80 persen transfer, yang tampaknya sia-sia karena server awalnya mengirimkannya sebagai byte dan pada akhirnya klien memerlukan byte lagi.
Base64 memecahkan masalah ini: JSON tidak memiliki tipe byte asli, jadi data biner harus dibungkus dalam sebuah string. Base64 mengonversi byte sembarang menjadi ASCII karakter yang aman di JSON. Baik klien maupun server harus menyandikan saat mengirim dan mendekode saat menerima, sehingga menambah overhead CPU. Payload yang dihasilkan sekitar sepertiga lebih besar dari byte mentah. Posting ini menjelaskan mengapa konvensi itu ada, berapa biayanya dalam praktiknya, dan kapan melanggar batasan JSON dengan titik akhir biner terpisah akan sepadan.
Mengapa JSON tidak dapat membawa byte mentah — string harus berupa teks Unicode yang valid, jadi byte arbitrer memerlukan pembungkus tekstual
JSON adalah format teks yang semua nilainya harus berupa teks Unicode yang valid. Spesifikasi mendefinisikan string, angka, boolean, dan null. Itu tidak memiliki array byte atau tipe buffer. Jika API perlu mengembalikan data biner seperti gambar, tanda tangan kriptografi, atau unggahan file, ia tidak dapat memasukkan byte mentah ke dalam objek JSON secara langsung. Byte mungkin berisi karakter yang ditafsirkan oleh parser JSON sebagai penanda struktural. Byte nol di tengah gumpalan biner dapat menghentikan string lebih awal atau merusak parser.
Solusi umumnya adalah mengkodekan data biner sebagai Base64, menghasilkan string karakter ASCII yang dianggap parser JSON sebagai teks biasa. Klien penerima kemudian menerjemahkan Base64 kembali ke byte dan menggunakannya. Langkah pengkodean ini terjadi pada tingkat API, tersembunyi dari sebagian besar pengembang, namun ini adalah biaya nyata yang terakumulasi ketika API mengembalikan banyak bidang biner. Biaya Base64 di JSON digabungkan di seluruh siklus permintaan-respons. Penalti ukuran adalah yang pertama: keluaran Base64 kira-kira 33 persen lebih besar dari masukannya karena overhead pengkodean.
Biaya: sepertiga byte lebih banyak, waktu dekode, dan salinan memori — di mana setiap biaya muncul di klien biasa
File video berukuran 30-megabita menjadi 40 megabita saat dikodekan Base64. Mengunduh 40 alih-alih 30 megabyte memerlukan bandwidth dan baterai pada perangkat seluler, serta waktu bagi pengguna dengan koneksi lambat. Biaya kedua adalah CPU kali. Server harus mengkodekan data biner sebagai Base64 sebelum dapat dirangkai menjadi JSON. Klien harus mengurai JSON dan kemudian mendekode setiap bidang Base64 kembali ke byte. Untuk respons dengan beberapa bidang biner atau klien yang memproses ribuan respons, waktu CPU tersebut terakumulasi.
Pada perangkat terbatas seperti ponsel, operasi string JavaScript dan TextDecoder yang digunakan untuk decoding Base64 menghabiskan baterai dan memperlambat aplikasi. Biaya ketiga adalah memori: parser JSON membuat objek string untuk bidang Base64, kemudian decoding membuat salinan lain sebagai Uint8Array. Bidang besar dibuat dua kali di memori sebelum aplikasi dapat menggunakannya. Contoh praktis memperjelas biayanya. Misalkan titik akhir API mengembalikan data profil pengguna termasuk gambar avatar 100-kilobyte. Server membaca gambar dari disk sebagai byte, mengkodekannya ke Base64, dan memasukkannya ke dalam respons JSON.
Contoh praktis: memeriksa bidang Base64 dari respons API — mendekodekannya di browser untuk mengonfirmasi apa yang sebenarnya dikirim oleh server
Respons JSON sekarang sekitar 135 kilobyte (overhead 33% ditambah kolom lainnya). Klien mengunduh 135 kilobyte, bukan 100. Di browser, parser JSON membuat objek string JavaScript untuk data Base64.
Saat aplikasi membutuhkan gambar, aplikasi akan memanggil dekoder Base64, yang membuat Uint8Array dari 100 kilobyte asli. Selama beberapa milidetik decoding, kedua objek ada di memori. Jika halaman tersebut menampilkan sepuluh profil dengan avatar, biayanya berlipat ganda. Alternatifnya adalah API mengembalikan respons JSON dengan URL terpisah untuk setiap sumber daya avatar, sehingga memungkinkan browser menangani pengunduhan gambar dengan cache aslinya, rendering progresif, dan manajemen memori.
Alternatif: URL unduhan multi-bagian dan terpisah, serta titik akhir biner mentah — masing-masing memiliki trade-off
Pertukaran antara menyertakan biner di JSON dan mengambilnya secara terpisah bergantung pada tujuan dan pola penggunaan API. Untuk laman hasil penelusuran yang menampilkan ratusan gambar mini kecil, mengambil masing-masing gambar kecil sebagai permintaan terpisah akan mengalahkan HTTP pengumpulan koneksi dan penyimpanan dalam cache. Menyebarkannya sebagai Base64 dalam respons JSON mungkin lebih cepat. Untuk halaman profil detail yang meminta satu atau dua gambar beresolusi tinggi, download terpisah jelas lebih baik. Dokumentasi API harus menyatakan ukuran maksimum bidang Base64 dan kapan klien mengharapkan titik akhir terpisah.
Jika suatu bidang sering melebihi satu atau dua kilobyte, strategi inline-Base64 adalah tanda bahwa desain API memerlukan pertimbangan ulang. Alternatif untuk Base64 di JSON ada tetapi masing-masing memiliki trade-off. Respons multipart MIME memisahkan biner dan teks sehingga bagian biner dikirim sebagai byte mentah dan hanya bagian teks yang JSON. Hal ini mengharuskan klien untuk mengurai pesan multibagian alih-alih hanya memanggil JSON.parse, sehingga menambah kerumitan. Unduhan terpisah URL dalam respons JSON mengarahkan klien untuk mengambil sumber daya biner secara terpisah.
Konvensi yang perlu dicantumkan dalam dokumen API Anda — alfabet, padding, dan ukuran maksimum url standar versus base64
Ini berfungsi dengan baik ketika sumber daya biner berukuran besar atau lebih jarang diakses dibandingkan metadata. Titik akhir biner mentah yang hanya mengembalikan byte dan mengabaikan JSON seluruhnya adalah pendekatan paling sederhana tetapi menghilangkan struktur yang disediakan JSON. Beberapa API mengembalikan data biner terkompresi dan mengkodekannya dengan Base64, sehingga mengurangi penalti ukuran tetapi menambahkan overhead dekompresi. Pilihannya bergantung pada penggunaan yang diharapkan: kolom kecil dapat disejajarkan, kolom besar berada dalam sumber daya terpisah, dan data terstruktur layak disimpan di JSON bahkan dengan biaya Base64.
Konvensi penting untuk interoperabilitas. API yang mengkodekan data biner Base64 harus mendokumentasikannya dengan jelas dan menyatakan apakah alfabetnya standar atau URL-aman. Base64 standar menggunakan + dan /, yang aman di string JSON tetapi tidak di URL. URL-safe Base64 menggantikannya dengan - dan _, yang sesuai untuk data: URI tetapi tidak perlu di-escape di JSON. Dokumentasi harus menentukan apakah padding disertakan atau dihilangkan, karena keduanya merupakan Base64 yang valid tetapi klien yang mengharapkan padding dan menerima data yang tidak diisi akan gagal secara diam-diam atau menghasilkan sampah.
Apa yang tidak tercakup di sini — protobuf, CBOR dan format serialisasi biner lainnya
Untuk bidang yang sangat besar atau sering diperbarui, mendokumentasikan titik akhir biner terpisah sangat penting sehingga klien tidak mencoba mengambil kilobyte data yang tidak diperlukan. Men-debug API dengan bidang Base64 sangatlah mudah dengan alat yang tepat. Encoder & decoder Base64 memungkinkan Anda mendekode bidang apa pun secara lokal di browser, tanpa menyimpannya atau mengirimnya ke mana pun. Salin bidang Base64 dari respons JSON, tempelkan ke decoder dan tekan Decode. Untuk data seperti teks (JSON di dalam Base64, misalnya), keluaran yang didekodekan akan langsung muncul.
Untuk data biner seperti gambar, tampilan hex menunjukkan byte. Ini membantu mengonfirmasi bahwa server mengirimkan apa yang Anda harapkan dan dekoder klien Anda berfungsi dengan benar. Jika suatu bidang didekodekan menjadi data yang tidak diharapkan, masalahnya ada pada pengkodean server atau cara Anda menyalin bidang tersebut. Jika diterjemahkan menjadi gumpalan parsial, bidang tersebut mungkin terpotong atau panjang Base64 mungkin salah. Dekode lokal mempercepat proses debug dibandingkan dengan menulis bidang ke file dan membuka alat eksternal.
Kesimpulan: Base64 di JSON adalah kompromi, jadi dokumentasikan — bagaimana encoder & decoder Base64 membantu Anda memeriksa dan memverifikasi bidang yang dikodekan secara lokal
Pendekatan praktis terhadap Base64 di API adalah kesadaran, bukan penghindaran. Base64 adalah cara standar untuk membawa data biner di JSON dan berfungsi. Pahami bahwa setiap kolom Base64 memerlukan biaya sepertiga lebih besar dan beberapa milidetik waktu CPU per siklus permintaan-respons. Untuk metadata penting kecil seperti token autentikasi (yang JWT sendiri dikodekan Base64), biayanya dapat diabaikan. Untuk lampiran besar, pertanyakan apakah biner harus berjalan dalam respons yang sama atau sebagai sumber daya terpisah.
Dokumentasikan skema pengkodean dan ukuran maksimum dalam spesifikasi API Anda. Saat memeriksa respons, gunakan encoder & decoder Base64 untuk memverifikasi dekode bidang dengan benar dan untuk memahami apa yang sebenarnya dikirim oleh server. Disiplin ini membuat trade-off tetap terlihat dan keputusan diambil secara sengaja dan bukannya tidak disengaja.