FlowingDev

Pesan HTTP, Dibedah Tuntas: Merakit Paket Mentah Web

Pelajari anatomi pesan mentah HTTP, dari baris awal dan header hingga body multipart yang kompleks, untuk memahami cara klien dan server web berkomunikasi.

Coba tool-nya: Pembuat Pesan HTTP

Dalam satu kalimat

Pesan HTTP adalah sebuah blok teks biasa terformat yang saling dipertukarkan oleh browser dan server web, berfungsi sebagai gabungan dari label pengiriman, buku panduan, dan isi paket untuk setiap interaksi di web.

Masalah yang dipecahkannya

Di masa-masa purba internet awal 1990-an, semuanya masih sederhana. Sebuah browser perlu cara untuk bertanya pada server, "Woy, boleh minta file science.html itu nggak?" dan server perlu cara untuk menjawab, "Boleh, nih," atau "Maaf, nggak ketemu." Percakapan ini butuh aturan—sebuah protokol. Protokol itulah yang menjadi HTTP, Hypertext Transfer Protocol.

"Masalah" yang dipecahkannya adalah menciptakan bahasa universal yang tidak ambigu untuk web. Tanpa format standar, satu server mungkin mengharapkan permintaan dalam satu baris, sementara yang lain mungkin butuh pantun. Bakal kacau balau. HTTP/0.9 versi awal sangatlah sederhana: GET /halaman-yang-kuinginkan.html. Server hanya akan langsung mengirimkan balik HTML-nya.

Tapi web tidak selamanya sederhana. Kita perlu mengirim data ke server untuk mengisi formulir. Kita perlu menangani berbagai jenis konten seperti gambar dan, belakangan, JSON. Kita butuh keamanan, caching, dan cara bagi browser untuk mendeskripsikan dirinya sendiri. Permintaan satu baris yang simpel itu berevolusi menjadi "pesan" multi-bagian yang terstruktur dengan baris-awal, blok metadata (header), dan body opsional untuk payload sebenarnya. Merakit pesan-pesan ini secara manual menjadi keahlian fundamental bagi siapa pun yang bekerja langsung dengan infrastruktur web, API, atau keamanan, memecahkan masalah tentang bagaimana cara melakukan urusan yang semakin kompleks melalui dialog permintaan-respons sederhana di web.

Cara kerjanya di balik layar

Pada dasarnya, pesan HTTP itu cuma teks biasa. Kamu benar-benar bisa mengetiknya di terminal lalu mengirimkannya ke server kalau kamu niat. Teks ini dibagi menjadi tiga bagian: baris-awal (start-line), blok header, dan body opsional, semuanya dipisahkan oleh pemisah baris spesifik (\r\n, atau CRLF singkatan dari "Carriage Return, Line Feed").

Ada dua jenis pesan: permintaan (request, dari klien ke server) dan respons (response, dari server ke klien). Keduanya terlihat hampir identik tetapi memiliki baris pertama yang berbeda.

Anatomi Pesan Request

Ini adalah saat browsermu meminta sesuatu.

GET /documentation/guides/http-builder HTTP/1.1
Host: flowing.dev
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0
Accept: text/html,*/*
Accept-Language: en-US,en;q=0.5
Connection: keep-alive

<-- Body seharusnya di sini, tapi request GET biasanya nggak punya -->
  1. Start-Line: GET /documentation/guides/http-builder HTTP/1.1

    • GET: method (atau verb) HTTP. Ini adalah apa yang ingin kamu lakukan. GET mengambil data, POST mengirim data baru, PUT memperbarui data yang ada, DELETE menghapus data.
    • /documentation/...: Path resource. Digabungkan dengan header Host, ini membentuk URL lengkap.
    • HTTP/1.1: Versi protokol.
  2. Header: Daftar pasangan kunci-nilai yang menyediakan metadata krusial tentang permintaan.

    • Host: flowing.dev: Untuk siapa permintaan ini? Header ini wajib di HTTP/1.1.
    • User-Agent: Mozilla/5.0...: Siapa yang mengirim permintaan ini? Browser mengidentifikasi dirinya.
    • Accept: text/html,*/*: Format respons seperti apa yang bisa saya mengerti? Di sini, browser lebih suka HTML tetapi akan menerima apa saja.
  3. Baris Kosong: Setelah header terakhir, satu baris kosong (\r\n) menandakan "header sudah selesai, selanjutnya adalah body." Ini tidak bisa ditawar. Menghilangkannya akan merusak segalanya.

  4. Body: Payload data yang sebenarnya. Untuk request GET, biasanya kosong. Untuk POST atau PUT, di sinilah data formulir atau payload JSON-mu berada.

Anatomi Pesan Respons

Ini adalah saat server membalas request.

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 15328
Server: Vercel
Date: Mon, 25 Sep 2023 10:30:00 GMT
Cache-Control: public, max-age=0, must-revalidate

<!DOCTYPE html>
<html>
  <head>...</head>
  <body>...</body>
</html>
  1. Status-Line: HTTP/1.1 200 OK

    • HTTP/1.1: Versi protokol, sama seperti request.
    • 200: Status Code. Angka tiga digit yang merangkum hasilnya. 2xx berarti sukses, 3xx berarti pengalihan (redirection), 4xx berarti kamu (klien) yang salah, dan 5xx berarti aku (server) yang salah.
    • OK: Reason Phrase. Ringkasan status code yang bisa dibaca manusia.
  2. Header: Metadata tentang respons.

    • Content-Type: text/html: "Body yang kukirimkan ini adalah HTML." Ini sangat penting agar browser tahu cara me-render payload.
    • Content-Length: 15328: "Body ini panjangnya persis 15.328 byte."
    • Set-Cookie: ...: Cara server memberitahu browser untuk menyimpan cookie.
    • Cache-Control: ...: Instruksi tentang bagaimana browser atau proxy perantara harus melakukan cache terhadap respons ini.
  3. Body: Resource yang diminta klien—HTML, CSS, objek JSON, data gambar, dll.

Pesta Pora Body: Mengenkode Payload

Ketika sebuah request memiliki body, ia memerlukan header Content-Type untuk menjelaskan formatnya. Tiga yang paling umum adalah:

  • application/x-www-form-urlencoded: Format default untuk formulir HTML jadul. Isinya hanyalah query string di dalam body.

    name=Grace+Hopper&title=Rear+Admiral
    
  • application/json: Raja para API modern. Body-nya adalah string JSON.

    {
      "name": "Grace Hopper",
      "title": "Rear Admiral"
    }
    
  • multipart/form-data: Format untuk mengirim formulir yang menyertakan unggahan file. Ini seperti pesan di dalam pesan. Body dipecah menjadi beberapa bagian, masing-masing dipisahkan oleh string "boundary". Setiap bagian dapat memiliki header mini-nya sendiri (seperti Content-Disposition dan Content-Type) dan kontennya sendiri.

    POST /profiles/edit HTTP/1.1
    Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
    
    ----WebKitFormBoundary7MA4YWxkTrZu0gW
    Content-Disposition: form-data; name="username"
    
    ada_lovelace
    ----WebKitFormBoundary7MA4YWxkTrZu0gW
    Content-Disposition: form-data; name="avatar"; filename="portrait.jpg"
    Content-Type: image/jpeg
    
    <...data biner mentah dari gambar ada di sini...>
    ----WebKitFormBoundary7MA4YWxkTrZu0gW--
    

Cerita dari dunia nyata

Kasus Content-Type yang Lenyap

Seorang developer sedang membangun REST API pertamanya. Endpoint-nya seharusnya menerima payload JSON untuk membuat pengguna baru. Dia menulis kode server dan mengujinya dengan tool baris perintah, mengirim objek JSON yang valid banget. Tapi server terus merespons dengan 400 Bad Request. Dia menghabiskan dua jam menatap JSON-nya, yakin ada koma yang terlewat. Dalam keputusasaan, dia meminta bantuan dev senior. Dev senior itu melihat request-nya sekali dan bertanya, "Di mana header Content-Type-mu?" Si developer telah mengirim data JSON, tetapi dia tidak pernah memberi tahu server bahwa itu adalah JSON. Framework di server, yang ngiranya bakal dapat x-www-form-urlencoded (format default), mencoba mem-parsing JSON tadi sebagai query string, gagal total, dan akhirnya menolak permintaan itu.

Pelajaran: Body sebuah pesan tidak ada artinya tanpa header Content-Type untuk memberinya konteks. Kamu harus memberi label pada paketmu dengan benar.

Kisruh Multipart

Sebuah tim sedang membuat halaman "pengaturan" di mana pengguna bisa mengubah nama mereka dan secara opsional mengunggah gambar profil baru. Dev frontend junior mengimplementasikannya dengan dua panggilan API terpisah: request PUT dengan nama pengguna dalam body JSON, dan kemudian, jika ada gambar yang dipilih, request POST dengan data gambar. Itu berhasil, tapi kaku, ribet, dan menciptakan race condition. Bagaimana jika perubahan nama berhasil tetapi unggahan gambar gagal? Pengguna akan berada dalam keadaan yang tidak konsisten. Seorang engineer backend melihat lalu lintas jaringan dan menariknya ke samping. "Ini adalah kasus penggunaan yang sempurna untuk multipart/form-data," jelasnya. Mereka me-refactor kode untuk membangun satu request POST tunggal dengan dua bagian: satu untuk field nama dan satu untuk file gambar. Ini menyederhanakan kode dan membuat seluruh pembaruan menjadi operasi atomik.

Pelajaran: multipart bukan hanya untuk file. Ini untuk mengirim sekantong data campuran—field teks, file, jenis konten yang berbeda—dalam satu request yang andal.

Hantu di dalam Cache

Sebuah situs e-commerce sedang mengadakan flash sale, tetapi pengguna mengeluh bahwa mereka melihat harga yang usang. Tim ops bingung; caching di sisi server mereka dikonfigurasi dengan benar. Seorang ahli performa web dipanggil. Alih-alih menggunakan dev tools browser, dia menggunakan tool untuk memeriksa respons HTTP mentah untuk halaman produk. Dia langsung menemukan biang keladinya. Sebuah load balancer yang salah konfigurasi di depan server web menyuntikkan headernya sendiri Cache-Control: public, max-age=3600, menimpa header Cache-Control: no-cache yang diinginkan server. Header nakal ini memberitahu browser dan CDN untuk melakukan cache harga selama satu jam, tidak peduli apa kata server aplikasi.

Pelajaran: Pesan HTTP mentah adalah sumber kebenaran tertinggi. Tool tingkat tinggi terkadang dapat menyembunyikan atau salah menafsirkan detail yang padahal jelas banget di dalam teks itu sendiri.

Kesalahan dan jebakan umum

  • Lupa baris kosong. Pesan HTTP harus memiliki CRLF (\r\n) antara header dan body. Jika hilang, parser akan menganggap body-mu hanyalah header lain yang salah format dan request akan gagal.
  • Content-Length yang tidak cocok. Jika kamu mendeklarasikan header Content-Length, nilainya harus ukuran byte yang persis sama dengan body. Jika terlalu kecil, datamu akan terpotong. Jika terlalu besar, server akan menunggu selamanya untuk byte yang tidak pernah datang.
  • Content-Type yang salah. Mengirim body JSON tetapi melabelinya sebagai text/plain adalah resep jitu untuk dapat eror 4xx. Header dan body harus sinkron.
  • CRLF vs. LF. Spesifikasi resmi menuntut \r\n untuk pemisah baris. Sebagian besar server modern cukup toleran dan akan menerima \n (Line Feed) sederhana. Namun, mengandalkan ini dapat menyebabkan request-mu gagal pada server, proxy, atau firewall yang lebih tua dan lebih kaku.
  • Encoding karakter khusus. Lupa melakukan URL-encode pada data dalam query string atau body x-www-form-urlencoded adalah bug klasik. Spasi harus menjadi %20, & harus menjadi %26, dan seterusnya, atau kamu berisiko merusak datamu.

Kenapa Ini Wajib Ada di Radarmu

Sebagian besar waktu, browser, framework, atau library-mu (seperti axios atau requests) menangani detail rumit dalam membangun pesan HTTP untukmu. Tetapi kamu harus tahu cara melakukannya secara manual ketika:

  • Kamu sedang deep-debugging. Ketika panggilan API tidak berfungsi dan pesan error-nya tidak jelas, memeriksa atau membuat ulang pesan HTTP mentah adalah wasit terakhir. Ini memungkinkanmu melihat persis apa yang dikirimkan lewat kabel, bebas dari abstraksi apa pun.
  • Kamu sedang membangun atau menguji API. Memahami struktur pesan adalah fundamental untuk merancang endpoint API yang baik dan menulis tes integrasi yang efektif. Para penguji keamanan menghabiskan hari-hari mereka merakit pesan yang sengaja dibuat cacat untuk menemukan kerentanan.
  • Kamu sedang melakukan scraping sebuah situs web. Untuk berhasil meniru browser sungguhan dan melewati langkah-langkah anti-bot, kamu sering kali perlu membuat request dengan kombinasi header yang sangat spesifik (User-Agent, Referer, Accept-*, dll.).
  • Kamu sedang bekerja dengan webhook. Ketika aplikasimu menerima webhook dari layanan seperti Stripe atau GitHub, kamu berada di pihak penerima request HTTP mentah. Kamu perlu mem-parsing headernya (misalnya, untuk signature keamanan) dan body-nya untuk menindaklanjuti event tersebut.

Mengetahui cara merakit pesan HTTP dari nol itu seperti montir yang paham cara kerja mesin pembakaran internal. Kamu tidak melakukannya setiap hari, tapi saat ada yang rusak, pengetahuan fundamental itu jadi tak ternilai harganya.

Gali lebih dalam

Teori beres. Saatnya praktik — 100% di browser kamu.

Coba tool-nya: Pembuat Pesan HTTP