FlowingDev

Penjelasan Percent-Encoding: memahami %20, %3F, dan hieroglif URL lainnya

Pelajari mengapa URL tidak bisa memuat karakter tertentu dan bagaimana percent-encoding mengubah karakter yang tidak aman menjadi format yang aman dan universal untuk web.

Coba tool-nya: Encoder URL

Dalam satu kalimat

URL encoding, yang secara resmi disebut percent-encoding, adalah proses menerjemahkan karakter yang punya arti khusus atau tidak valid di dalam URL menjadi format yang aman dan dipahami secara universal agar bisa dikirim tanpa menyebabkan kebingungan.

Masalah yang dipecahkannya

Di masa-masa awal web yang masih purba, hidup itu sederhana. URL—atau lebih luasnya, URI (Uniform Resource Identifiers)—dirancang untuk menjadi cara yang bersih dan bisa ditebak untuk menemukan sebuah sumber daya. Para arsiteknya, termasuk Sir Tim Berners-Lee, membangun sistem ini di atas fondasi set karakter yang terbatas: ASCII.

Ini berjalan lancar, selama kamu cuma perlu menunjuk ke http://example.com/reports/April.html. Tapi apa yang terjadi kalau situasinya jadi lebih rumit?

Coba perhatikan anatomi sebuah URL. URL punya beberapa bagian: scheme (http:), host (example.com), path (/search), dan mungkin query string (?q=dogs&cats). Karakter-karakter tertentu berperan sebagai sutradara struktural dalam drama ini. Titik dua (:) memisahkan scheme. Garis miring (/) memisahkan segmen path. Tanda tanya (?) memulai parameter kueri. Simbol dan (&) memisahkan satu parameter dari parameter berikutnya.

Di sinilah masalah mulai muncul. Gimana kalau kamu mau mencari string harfiah "C++ & C#"? Kalau kamu langsung menempelkannya ke URL, kamu akan dapat .../search?q=C++ & C#. Sebuah server web yang melihat ini bakal bingung setengah mati. Ia akan berpikir kuerinya adalah untuk "C++ ", lalu ia melihat simbol dan dan berharap ada pasangan key-value lain, tapi yang didapat cuma " C#" yang sendirian. Kacau balau. Makna yang dimaksud jadi hilang.

Lebih jauh lagi, beberapa karakter memang tidak diizinkan. Spasi adalah biang keladi klasik. Kapan sebuah spasi dianggap bagian dari nama file, dan kapan itu hanya salah ketik yang harus diabaikan oleh browser? Dan bagaimana dengan karakter di luar alfabet Inggris dasar? Web ini kan global! Gimana caranya kamu menaruh Résumé.pdf atau 你好.html di dalam URL yang dirancang untuk ASCII?

Percent-encoding memecahkan seluruh kelas masalah ini. Ia menyediakan sebuah pintu darurat, sebuah cara untuk bilang, "Hei, Pak Server Web, karakter(-karakter) berikutnya ini bukan struktural. Jangan diinterpretasikan. Ini adalah data harfiah." Ia adalah penerjemah universal yang memastikan sebuah URL punya arti yang sama di browser di Brazil maupun di server di Berlin.

Cara kerjanya di balik layar

"Sihir" di balik percent-encoding ternyata sangat sederhana. Ini bukan trik sulap, lebih mirip sandi substitusi sederhana yang sudah disepakati semua orang untuk dipakai.

Para Pemeran: Karakter Reserved vs. Unreserved

Pertama, kamu perlu tahu karakter mana yang aman-aman saja dan mana yang bermasalah. Mereka terbagi dalam beberapa kelompok.

Jenis Karakter Karakter Kapan Harus di-Encode
Unreserved A-Z a-z 0-9 - _ . ~ Jangan pernah. Ini adalah para VIP di dunia URL. Mereka selalu aman.
Reserved : / ? # [ ] @ ! $ & ' ( ) * + , ; = Terkadang. Karakter-karakter ini punya arti struktural khusus. Kalau kamu mau memakainya sesuai artinya (seperti / di dalam path), kamu tidak perlu encode. Kalau kamu mau memakainya sebagai data literal (seperti & dalam kueri pencarian), kamu wajib encode.
Lainnya (Tidak Aman) (spasi), `< > " % { } \ ^` dan semua karakter non-ASCII

Poin kuncinya adalah konteks. Karakter ? tidak masalah jika itu adalah satu-satunya ? yang memisahkan path dari query string. Tapi jika kamu butuh tanda tanya harfiah di dalam nilai parameter kueri, kamu harus melakukan encode.

Trik Sulapnya: Persen + Hex

Proses encoding-nya adalah tarian tiga langkah yang simpel:

  1. Pilih sebuah karakter yang perlu kamu encode. Mari kita pakai simbol dan &.
  2. Cari nilai byte-nya menggunakan set karakter standar. Untuk web, standarnya adalah UTF-8. Dalam UTF-8 (dan pendahulunya, ASCII), karakter & direpresentasikan oleh angka desimal 38.
  3. Ubah angka itu menjadi dua digit heksadesimal dan tambahkan tanda persen (%) di depannya. Desimal 38 adalah 26 dalam heksadesimal.

Jadi, & menjadi %26.

Mari kita coba beberapa lagi:

  • Spasi adalah desimal 32, yaitu hex 20. Hasil encode: %20.
  • Tanda tanya (?) adalah desimal 63, yaitu hex 3F. Hasil encode: %3F.
  • Tanda persen (%) itu sendiri adalah desimal 37, hex 25. Jadi untuk meng-encode % secara harfiah, kamu menulis %25.

Sistem ini brilian karena tanda persen itu sendiri bukan karakter unreserved, jadi parser tahu bahwa setiap kali ia melihat %, ia harus mengharapkan dua digit hex berikutnya.

Bagaimana dengan karakter non-Inggris?

Di sinilah UTF-8 jadi krusial. Karakter ASCII sederhana seperti A adalah satu byte. Tapi karakter seperti é dari Prancis atau 好 dari Tiongkok direpresentasikan oleh beberapa byte dalam UTF-8. Proses encoding-nya sama saja, hanya diulang untuk setiap byte.

Mari kita ambil é:

  1. Dalam UTF-8, é direpresentasikan oleh dua byte: C3 dan A9 (dalam hex).
  2. Encode setiap byte secara terpisah:
    • C3 menjadi %C3.
    • A9 menjadi %A9.
  3. Gabungkan keduanya: é menjadi %C3%A9.

Proses decoding-nya adalah kebalikannya. Sebuah browser atau server melihat %C3%A9, mengambil dua byte C3 dan A9, menjalankannya melalui decoder UTF-8, dan mendapatkan kembali karakter é yang cantik.

Kisah di dunia nyata

Teori memang bagus, tapi mari kita lihat praktiknya di lapangan.

Kasus Kueri Pencarian yang Menghilang

Seorang developer junior, Maya, sedang membuat fitur pencarian untuk situs dokumentasi teknis. Pengguna bisa mencari hal-hal seperti "C++", "promises & async/await", dan sebagainya. Dia membuat URL pencarian hanya dengan menggabungkan string: site.com/search?q= + userInput.

Semuanya jadi kacau balau. Pencarian untuk promises & async/await menghasilkan URL .../search?q=promises & async/await. Servernya, ternyata, hanya melaporkan kata kunci pencariannya sebagai "promises ". Karakter & diartikan sebagai pemisah untuk parameter baru, async/await, yang kemudian dibuang karena tidak punya key. Hasil pencariannya jadi salah total.

Pelajaran: Maya belajar aturan utama pengembangan web: selalu lakukan percent-encode pada data dinamis apa pun yang dimasukkan ke dalam komponen URL. Setelah dia mulai meng-encode input pengguna, URL-nya menjadi benar: .../search?q=promises%20%26%20async%2Fawait. Server sekarang menerima string yang lengkap dan benar, dan pencarian pun berfungsi dengan sempurna.

Insiden Internasional

Sebuah toko online memutuskan untuk mempromosikan produk baru dari mitra di Jerman: "Fußball." Tim marketing membuat URL yang ramah untuk produk itu: store.com/products/Fußball. Di browser modern mereka di kantor, semuanya tampak baik-baik saja.

Tapi hari peluncurannya berantakan. Tiket dukungan pelanggan membanjir. Beberapa pengguna mendapatkan eror "404 Not Found". Yang lain melihat URL yang tampak seperti .../products/Fu%C3%9Fball di bilah alamat browser mereka, sementara beberapa melihat .../products/FuÃball. Sistem mereka ternyata merupakan tambal sulam komponen lama dan baru, dan mereka tidak menangani karakter non-ASCII ß (Eszett) secara konsisten. Beberapa bagian tidak meng-encode-nya, beberapa meng-encode dengan asumsi UTF-8, dan beberapa sistem lawas men-decode-nya dengan asumsi set karakter yang berbeda, menghasilkan mojibake (karakter yang rusak/salah tampil).

Pelajaran: Mengandalkan browser dan server untuk "langsung menangani" karakter non-ASCII di URL adalah resep untuk inkonsistensi. Secara proaktif dan konsisten melakukan percent-encoding pada semua karakter non-unreserved menggunakan standar UTF-8 akan memastikan URL kamu kuat dan bekerja dengan dapat diprediksi di seluruh ekosistem web, baik yang lama maupun yang baru.

Bencana Double-Encoding

Sebuah tim sedang membangun sistem single sign-on (SSO). Alurnya seperti ini: service-a.com akan mengalihkan pengguna ke sso.com/login, sambil mengirimkan URL-nya sendiri sebagai parameter agar pengguna bisa dikirim kembali setelah login. URL pengalihannya terlihat seperti ini: sso.com/login?redirect_uri=https://service-a.com/dashboard?param=1.

Developer di service-a.com cukup pintar dan melakukan encode pada nilai redirect_uri, menghasilkan: sso.com/login?redirect_uri=https%3A%2F%2Fservice-a.com%2Fdashboard%3Fparam%3D1.

Namun, web framework yang mereka gunakan punya sebuah lapisan middleware yang, "demi keamanan," secara otomatis melakukan URL-encode pada semua parameter kueri yang keluar. Middleware itu melihat string yang sudah di-encode dan meng-encode-nya lagi. Karakter % di %3A diubah menjadi %25, jadi %3A menjadi %253A. URL akhirnya menjadi kekacauan hasil double-encoding yang tidak karuan. Ketika pengguna mendarat di sso.com, sistem itu men-decode URL-nya sekali dan mendapatkan string yang masih ter-encode satu kali, yang tidak bisa digunakannya sebagai pengalihan, sehingga merusak alur login sepenuhnya.

Pelajaran: Sadari seluruh rantai alat yang kamu gunakan. Encode data pada titik pembuatannya, dan pastikan tidak ada sistem lain di jalur tersebut yang meng-encode-nya lagi. Double-encoding adalah bug umum yang bikin garuk-garuk kepala, yang mengubah URL valid menjadi sampah tak berguna.

Kesalahan dan jebakan umum

  • Melakukan encode pada seluruh URL. Jangan pernah lakukan ini. Jika kamu melakukan percent-encode pada https://example.com, kamu akan mendapatkan sesuatu seperti https%3A%2F%2Fexample.com. Ini bukan lagi URL yang valid; bagian scheme dan authority-nya sekarang jadi sekumpulan karakter acak yang tidak berarti. Kamu hanya boleh meng-encode komponen individual yang memerlukannya (seperti nilai parameter kueri atau segmen path tertentu).
  • Tidak melakukan encode sama sekali. Dosa yang paling sering terjadi. Memasukkan input mentah dari pengguna atau data dengan karakter khusus langsung ke dalam string URL sama saja dengan mengundang lubang keamanan (seperti Cross-Site Scripting) dan fungsionalitas yang rusak.
  • Lupa soal konteks. Karakter & tidak masalah di dalam path URL, tapi itu adalah pemisah yang di-reserve di dalam query string. Begitu juga dengan /. Kamu tidak perlu meng-encode karakter reserved ketika mereka digunakan untuk tujuan khususnya.
  • Bingung membedakan + dengan %20. Dalam tipe konten application/x-www-form-urlencoded (digunakan oleh form HTML), spasi sering di-encode sebagai tanda + di query string. Meskipun banyak server memahami ini, percent-encoding resmi untuk spasi adalah %20. Menggunakan %20 tidak ambigu dan berfungsi dengan benar di semua bagian URL, bukan hanya di query string. Kalau ragu, pakai saja %20.
  • Menggunakan set karakter yang sudah usang. Web berjalan di atas UTF-8. Jika kamu meng-encode data menggunakan set karakter yang berbeda (seperti ISO-8859-1), maka server yang mengharapkan UTF-8 akan salah menafsirkan byte dan merusak datamu. Selalu tentukan dan gunakan UTF-8.

Kenapa ini harus kamu perhatikan

Kalau kamu menulis kode yang bersentuhan dengan URL, kamu wajib paham percent-encoding. Ini bukan pilihan. Kamu harus memikirkannya setiap kali kamu:

  • Membangun sebuah URL dari variabel atau input pengguna.
  • Membuat permintaan API dengan parameter di URL.
  • Menangani karakter internasional dalam nama file, profil pengguna, atau konten yang mungkin muncul di URL.
  • Mem-parsing URL di sisi server untuk mengekstrak data.
  • Menulis pengalihan atau mengirim URL sebagai parameter ke layanan lain.

Singkatnya, percent-encoding adalah bagian fundamental dari pipa ledeng web. Mengabaikannya akan menghasilkan perangkat lunak yang penuh bug, tidak aman, dan tidak bisa diandalkan. Mengetahui cara kerjanya adalah tanda seorang developer web profesional.

Pelajari lebih dalam

  • RFC 3986: Spesifikasi kanonis untuk Uniform Resource Identifier (URI). Bagian 2 mendefinisikan set karakter dan aturan percent-encoding. Ini adalah sumber kebenaran tertinggi.
  • MDN Web Docs: encodeURIComponent(): Panduan praktis untuk developer JavaScript, menjelaskan fungsi mana yang harus digunakan dan mengapa. Bagian "See also" menautkan ke fungsi encoding terkait lainnya.
  • Wikipedia: Percent-encoding: Gambaran umum yang komprehensif dan sangat mudah dibaca tentang konsep ini, sejarahnya, dan berbagai nuansanya.
  • W3C: Character encodings: Pengantar tingkat tinggi tentang mengapa character encoding itu penting di web, dengan UTF-8 sebagai pahlawan ceritanya.

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

Coba tool-nya: Encoder URL