Episode ini membahas format pesan WebSocket: teks dan JSON, binary ArrayBuffer dan Blob, format terstruktur seperti MessagePack dan protobuf, kompresi, serta pola envelope untuk pesan yang stabil terhadap perubahan.

Sejauh ini kalian mengirim pesan lewat WebSocket sebagai teks. Tapi protokol WebSocket tidak peduli isi pesan — yang dikirim bisa teks, binary, atau campuran keduanya. Keputusan bagaimana mengemas data justru menentukan kecepatan, ukuran, dan ketahanan aplikasi kalian.
Episode 10 membahas serialization: mengubah objek menjadi byte yang bisa dikirim, dan data format: struktur yang dipakai untuk membungkus pesan. Dari JSON yang sederhana hingga protobuf yang ringkas, kalian akan tahu kapan memilih yang mana.
Format paling umum untuk aplikasi WebSocket adalah JSON. Simpel, mudah dibaca manusia, dan didukung semua bahasa.
const pesan = {
type: "chat",
room: "nodejs",
teks: "Halo semuanya!",
waktu: Date.now(),
};
ws.send(JSON.stringify(pesan));
ws.on("message", (data) => {
const terima = JSON.parse(data.toString());
console.log(terima.type, terima.teks);
});JSON.stringify(pesan) mengubah objek menjadi string sebelum dikirim, dan JSON.parse(...) mengembalikannya menjadi objek di sisi penerima. Wajib dibungkus try-catch karena parse bisa gagal saat menerima data rusak.
Data dari jaringan tidak bisa dipercaya. Satu karakter salah bisa membuat seluruh aplikasi crash.
ws.on("message", (data) => {
try {
const pesan = JSON.parse(data.toString());
prosesPesan(pesan);
} catch {
ws.send(JSON.stringify({ error: "format pesan tidak valid" }));
}
});Pola try-catch di atas mencegah satu pesan rusak mematikan proses server. Kirim respons error agar klien bisa memperbaiki diri, lalu lanjut memproses pesan berikutnya.
Untuk data seperti gambar, audio, atau file, binary jauh lebih efisien daripada teks. Browser memberikan dua representasi: ArrayBuffer dan Blob.
ws.binaryType = "arraybuffer";
ws.onmessage = (event) => {
if (typeof event.data === "string") {
console.log("pesan teks:", event.data);
} else {
const buffer = new Uint8Array(event.data);
console.log("pesan binary:", buffer.length, "byte");
}
};
const bytes = new Uint8Array([1, 2, 3, 4]);
ws.send(bytes.buffer);ws.binaryType = "arraybuffer" mengatur cara browser menyajikan data binary yang masuk. Pengiriman binary memakai ws.send(bytes.buffer) — ArrayBuffer atau Blob dikirim langsung tanpa serialisasi.
Binary hemat bandwidth dan lebih cepat diproses, tapi tidak bisa dibaca manusia. Aturan praktisnya: gunakan JSON untuk metadata dan pesan kecil, binary untuk data yang besar atau sudah terstruktur sebagai byte.
Jika aplikasi membutuhkan ukuran payload minimal dan kecepatan tinggi, ada format binary terstruktur.
bun add @msgpack/msgpackMessagePack mengubah objek menjadi binary yang jauh lebih kecil dari JSON, sementara Protocol Buffers (protobuf) membutuhkan skema .proto dan menghasilkan encoding paling ringkas. Untuk aplikasi kecil, perbedaan ini jarang terasa; untuk jutaan pesan per hari, ia sangat berarti.
Ekstensi permessage-deflate mengompresi pesan saat dikirim dan mendekompresi saat diterima, transparan untuk kalian sebagai developer.
const { WebSocketServer } = require("ws");
const wss = new WebSocketServer({
port: 8080,
perMessageDeflate: true,
});perMessageDeflate: true mengaktifkan kompresi di server ws. Perhatikan trade-off: kompresi menambah latensi CPU dan memori, jadi untuk pesan kecil yang tidak berulang, mematikannya justru lebih cepat.
Setiap pesan dibungkus dengan struktur tetap yang memuat tipe dan payload. Ini disebut envelope.
const envelope = {
v: 2,
type: "message:send",
id: "msg_7f3a",
data: {
to: "user:12",
teks: "Halo!",
},
};Field type menentukan bagaimana penerima memproses payload, id untuk tracking dan deduplikasi, dan v untuk versi protokol. Dengan envelope, kalian bisa menambah event baru tanpa memecah klien lama.
Saat protokol berkembang, gunakan field versi untuk memigrasi klien secara bertahap.
function prosesEnvelope(envelope) {
if (envelope.v !== 2) {
return { error: "versi protokol tidak didukung" };
}
return prosesBerdasarkanTipe(envelope);
}Cek versi di awal memungkinkan server menolak klien tua dengan pesan yang jelas, atau menjalankan transformasi untuk kompatibilitas mundur.
Episode 10 membuat kalian sadar bahwa isi pesan WebSocket adalah keputusan desain, bukan sesuatu yang ditentukan protokol. JSON untuk kemudahan, binary untuk efisiensi, format terstruktur untuk skala besar, dan envelope untuk evolusi protokol.
Inti yang harus dibawa pulang:
Di episode 11 berikutnya kita membahas presence & heartbeat mechanisms: ping-pong frame, deteksi koneksi mati, status online dan offline pengguna, serta pengaturan interval heartbeat di Socket.IO.