Topik wawancara representatif

Wawancara frontend: Bagaimana Anda memproses file besar secara aman dengan Compression Streams?

FrontendSulit
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Browser harus melakukan gzip pada unggahan besar dan mendekompresi unduhan dengan penggunaan memori rendah, dukungan pembatalan, serta perlindungan dari input berbahaya. Rancang pipeline stream dan jelaskan format, backpressure, error, dan batasan keamanannya.

Permintaan dan konteks

Browser harus melakukan gzip pada unggahan besar dan mendekompresi unduhan dengan penggunaan memori rendah, dukungan pembatalan, serta perlindungan dari input berbahaya. Rancang pipeline stream dan jelaskan format, backpressure, error, dan batasan keamanannya.

Compression Streams API menyediakan CompressionStream dan DecompressionStream untuk chunk biner dalam pipeline Web Streams. Standar ini mendefinisikan brotli, deflate, deflate-raw, dan gzip; API ini menyediakan fungsi transformasi, bukan batasan ukuran, autentikasi, atau pemeriksaan integritas bisnis.

Apa yang diuji oleh pewawancara

Mencakup komposisi Readable/Writable/TransformStream, backpressure dan antrean, flush, batasan format, error dekompresi, propagasi pembatalan, batas alokasi memori (memory budget), decompression bomb dan length side channels, progressive enhancement, serta negosiasi server.

Kerangka jawaban 30 detik

“Saya akan menghubungkan stream Blob atau body respons ke CompressionStream menggunakan pipeThrough agar backpressure tetap terjaga, dan mempropagasi pembatalan dengan AbortSignal. Pada proses unduh, batasi ukuran terkompresi, byte hasil dekompresi, dan waktu pemrosesan sebelum meneruskan DecompressionStream ke parser; batalkan jika terjadi error format atau integritas. Jika browser tidak memiliki kapabilitas ini, lakukan fallback ke kompresi server. API ini bukan pemindai keamanan atau pemverifikasi integritas.”

Pembahasan mendalam langkah demi langkah

Langkah 1: Memilih stream input dan output

Unggahan dapat dimulai dari Blob.stream() dan unduhan dari Response.body. Sebuah CompressionStream menghasilkan ReadableStream untuk fetch body, file sink, atau parser; jangan memuat seluruh file ke dalam ArrayBuffer terlebih dahulu.

Langkah 2: Menghubungkan transformasi

Pipeline unggahan minimal adalah:

javascript
async function uploadGzip(blob, signal) {
  const compressed = blob.stream().pipeThrough(
    new CompressionStream("gzip"),
    { signal },
  );
  return fetch("/upload", {
    method: "POST",
    body: compressed,
    signal,
    headers: { "Content-Encoding": "gzip" },
  });
}

Protokol sebenarnya harus mendefinisikan panjang permintaan, semantik percobaan ulang (retry), dan apakah server menerima streaming body permintaan.

Langkah 3: Memahami backpressure dan flush

Streams API menyesuaikan pembacaan di sisi hulu (upstream) berdasarkan antrean dan kecepatan tulis di sisi hilir (downstream). Jangan memasukkan setiap chunk ke dalam array tanpa batas; sink yang lambat harus menjeda pipeline secara alami. Menutup sisi writable harus memicu flush pada blok terkompresi akhir dan checksum.

Langkah 4: Menegosiasikan format

Konstruktor menerima string format yang didukung dan melempar exception jika format tidak didukung. Klien dan server harus menyepakati Content-Encoding atau field bisnis tertentu. deflate, deflate-raw, dan gzip memiliki pembungkus (wrapper) yang berbeda; jangan mengirim Brotli tanpa negosiasi terlebih dahulu.

Langkah 5: Membatasi proses dekompresi

Input yang terkompresi dapat mengembang menjadi output yang sangat besar. Hitung byte output, entri file, waktu pemrosesan, dan tugas bersamaan (concurrent jobs); batalkan atau hentikan segera setelah batas anggaran terlampaui. Konten yang didekompresi tetap memerlukan pemeriksaan MIME, jalur, dan keamanan konten. Transformasi yang berhasil tidak menjamin data tersebut dapat dipercaya.

Langkah 6: Mempropagasikan error dan pembatalan

Kegagalan format atau checksum akan mengubah status transformasi menjadi errored. Tangkap error dari pipeTo, fetch, dan reader, lalu variasikan pembatalan oleh pengguna ke permintaan, reader, writer, dan transform. Lepaskan Blob sementara, kunci (locks), dan status progres UI sehingga tidak ada proses pembacaan yang tertunda.

Langkah 7: Melindungi privasi dan integritas

Panjang data terkompresi dapat mengungkap hubungan antara data rahasia dan teks yang dikontrol oleh penyerang. Jangan menempatkan keduanya dalam satu konteks kompresi yang sama. Gunakan tanda tangan (signature) atau hash independen untuk file penting; kompresi hanya menyandikan byte, bukan mengautentikasi sumber atau mencegah manipulasi.

Langkah 8: Menyediakan kompatibilitas dan fallback

Periksa konstruktor dan format saat aplikasi dimulai, dan jalankan tugas berat di dalam Worker untuk melindungi main thread. Jika tidak didukung, delegasikan ke kompresi server atau unggah tanpa kompresi dengan semantik pembatalan, ukuran, dan penanganan error yang sama; jangan hanya melakukan validasi pada browser modern.

Trade-off dan batasan

CPU klien versus penghematan jaringan

Kompresi menghemat transfer byte tetapi mengonsumsi CPU, baterai, dan waktu. Pada perangkat seluler, tentukan pilihan berdasarkan jenis file, kualitas jaringan, dan daya baterai; format yang sudah terkompresi biasanya tidak perlu dikompresi ulang.

Streaming versus kesederhanaan retry

Streaming menjaga penggunaan memori tetap rendah tetapi membutuhkan server yang memahami chunk serta mekanisme retry yang idempoten. Untuk unggahan yang dapat dilanjutkan (resumable), tautkan chunk terkompresi ke protokol multipart; jangan mencoba ulang ReadableStream yang sudah terkonsumsi seolah-olah stream tersebut dapat diputar ulang (replayable).

Dekompresi browser versus server

Dekompresi di browser menghemat CPU server tetapi memindahkan beban sumber daya dan batas keamanan ke perangkat. Untuk data yang sensitif atau memiliki rasio ekspansi sangat tinggi, lakukan dekompresi di server dan kembalikan hasil yang telah dibatasi, sementara klien mengonsumsi status dan chunk.

Latihan simulasi kegagalan dan rencana evolusi

Sink menjadi lambat

Batasi kecepatan unggah (throttle) dan periksa grafik antrean serta memori. Pastikan tidak semua chunk tertahan di memori; jika antrean tetap bertambah, kurangi konkurensi dan biarkan pipeline menjeda secara otomatis.

Stream gzip terpotong (truncated)

Potong input terkompresi dan verifikasi terjadinya kegagalan saat flush atau validasi checksum, pastikan UI masuk ke status dapat dicoba ulang (retryable), serta lepaskan reader, request, dan objek sementara.

Output melebihi batas anggaran

Gunakan sampel data dengan ekspansi tinggi dan verifikasi bahwa mencapai batas byte akan langsung membatalkan operasi, alih-alih mewujudkan atau menyimpan seluruh output ke penyimpanan.

Kesalahan umum dan pertanyaan lanjutan

Kesalahan 1: Menganggap API mencegah decompression bomb

Pertanyaan lanjutan: Apa yang kurang? Batas anggaran tingkat aplikasi untuk byte, waktu, entri, dan konkurensi; API ini hanya melakukan konversi format.

Kesalahan 2: Menganggap deflate sama dengan gzip

Pertanyaan lanjutan: Mengapa tidak? Struktur pembungkusnya berbeda, sehingga diperlukan negosiasi protokol dan pencocokan format.

Kesalahan 3: Mencoba ulang stream yang sudah terkonsumsi

Pertanyaan lanjutan: Apa langkah yang benar? Bangun kembali pipeline dari sumber chunk atau Blob yang dapat diputar ulang dan koordinasikan identifier unggahan yang idempoten dengan server.

Pertanyaan lanjutan tambahan dan contoh jawaban

Mengapa proses flush penting?

Transformasi harus memancarkan data kompresi trailer dan checksum saat input berakhir. Tanpa menutup sisi writable, konsumen dapat menerima stream yang tidak lengkap.

Bagaimana cara mengurangi risiko length side-channel?

Pisahkan data rahasia dari teks yang dikontrol penyerang, hindari konteks kompresi bersama, dan gunakan padding protokol atau rancangan yang tidak mengekspos hubungan antar-data tersebut.

Kapan kompresi sebaiknya tetap dilakukan di server?

Gunakan pemrosesan di sisi server untuk browser lama, perangkat dengan baterai lemah, file berukuran raksasa, atau data sensitif. Tetap batasi output yang didekompresi dan tampilkan progres yang dapat dipantau ke klien.

Sumber publik

Pertanyaan terkait