Pengode / pendekode URL

Persen-kodekan dan dekode URL, pilih cakupan komponen atau URL penuh, dan lihat URL terurai menjadi bagian-bagiannya.

Untuk satu nilai seperti satu parameter kueri. Meng-escape / ? : @ & = + pula, karena di sana mereka data ketimbang struktur.

Masukan
Keluaran

Keluaran akan muncul di sini

Untuk apa persen-pengodean

Sebuah URL hanya diizinkan mengandung sekumpulan kecil karakter: huruf A–Z dan a–z, digit, segelintir tanda seperti - . _ ~, dan sekumpulan karakter yang dipesan yang memberi alamat bentuknya — / ? # & = : @ dan beberapa lagi. Apa pun yang lain, dari sebuah spasi hingga sebuah kata Ibrani hingga sebuah emoji, harus direpresentasikan secara tak langsung. Persen-pengodean adalah representasi itu: karakternya diubah ke bita UTF-8-nya dan tiap bita ditulis sebagai sebuah tanda persen diikuti dua digit heksadesimal. Sebuah spasi menjadi %20, dan א menjadi %D7%90.

Karakter yang dipesan adalah kasus yang menarik. Mereka sah dalam sebuah URL, tetapi mereka berarti sesuatu yang struktural: ? memulai kueri, & memisahkan parameter, = membelah sebuah kunci dari nilainya. Ketika salah satu karakter itu adalah bagian dari data Anda ketimbang bagian dari struktur, ia harus dikodekan — jika tidak pengurai di ujung lain akan membacanya sebagai tanda baca dan membelah nilai Anda di tempat yang salah.

Komponen atau URL penuh — perbedaan yang merusak tautan

Ini adalah sumber tunggal paling umum bug URL, dan itu sebabnya alat ini meminta Anda memilih sebuah cakupan ketimbang menebak.

  • Cakupan komponen meng-escape pembatas pula: / ? : @ & = + $ , dan #. Pakai untuk satu potong data — sebuah istilah pencarian, target pengalihan, sebuah token — yang ditaruh di dalam sebuah URL yang lebih besar.
  • Cakupan URL penuh membiarkan pembatas itu dan meng-escape hanya yang benar-benar ilegal, seperti spasi dan teks non-ASCII. Pakai ketika Anda punya alamat lengkap yang sudah terstruktur dengan benar dan sekadar perlu dibersihkan.

Salah di arah mana pun dan sesuatu rusak. Kodekan seluruh URL dalam cakupan komponen dan setiap garis miring dan tanda tanya berubah menjadi %2F dan %3F, menghasilkan satu string panjang yang tak terpakai. Kodekan satu nilai dalam cakupan URL penuh dan sebuah ampersand di dalamnya bertahan sebagai pembatas, jadi sebuah pencarian untuk "cats & dogs" diam-diam menjadi dua parameter dan separuh kedua nilai Anda lenyap.

// The value contains a delimiter, so it must be escaped:
const q = 'cats & dogs'
`/search?q=${encodeURIComponent(q)}`  // /search?q=cats%20%26%20dogs
`/search?q=${encodeURI(q)}`           // /search?q=cats%20&%20dogs  ✗

// Better still, let the platform assemble it:
const url = new URL('https://example.com/search')
url.searchParams.set('q', 'cats & dogs')

Pendekatan terakhir itu layak diadopsi sebagai kebiasaan. URL dan URLSearchParams dibangun ke dalam setiap browser dan ke dalam Node, dan mereka menerapkan pengodean yang tepat ke tiap bagian untuk Anda — yang menghapus keputusannya sepenuhnya ketimbang membuat Anda melakukannya dengan benar dengan tangan setiap kali.

Mengapa spasi kadang + dan kadang %20

Dua spesifikasi berbeda sedang bekerja, dan mereka tak sepakat tentang persis satu karakter. RFC 3986, yang mengatur URL secara umum, mengodekan sebuah spasi sebagai %20. Format application/x-www-form-urlencoded yang lebih lama, yang adalah yang dikirim formulir HTML dan karenanya seperti apa kebanyakan string kueri, mengodekan sebuah spasi sebagai +.

Jebakannya adalah decodeURIComponent hanya mengimplementasikan aturan pertama. Beri ia hello+world dan Anda mendapatkan hello+world kembali, plus dan semuanya — tanpa galat, tanpa peringatan, hanya sebuah nilai yang secara halus salah. Itulah sebabnya alat ini menawarkan opsi "perlakukan + sebagai spasi" dan menunjuknya ketika masukan Anda mengandung sebuah plus sementara opsi itu mati.

Perhatikan bahwa URLSearchParams, yang menenagai tabel uraian di bawah alat, mengikuti aturan formulir dan memang mengubah + ke sebuah spasi. Jadi string kueri yang sama bisa didekode berbeda bergantung pada API mana yang Anda raih — secara sengaja, dan benar, di kedua kasus.

Satu konsekuensi yang layak diingat: jika sebuah plus benar-benar bagian dari data Anda — sebuah nomor telepon, sebuah ekspresi filter — ia harus dikodekan sebagai %2B. Sebuah + harfiah dalam sebuah string kueri paling baik ambigu dan akan dibaca sebagai sebuah spasi oleh kebanyakan pengurai.

Membaca sebuah URL

Tempel sebuah URL absolut dan alat membelahnya menjadi bagian-bagiannya. Layak tahu apa nama masing-masing, karena pesan galat dan dokumentasi mengasumsikan kosakatanya:

  • Skema — https, mailto, ftp. Segalanya sebelum titik dua, dan hal yang memutuskan bagaimana sisanya ditafsirkan.
  • Info pengguna — sebuah user:password opsional sebelum host. Masih sah, dan masih ide buruk: ia berkelana dengan setiap permintaan dan mendarat di log, riwayat browser, dan header perujuk.
  • Host — nama domain atau alamat IP. Segalanya setelahnya ditangani server itu, bukan jaringan.
  • Port — biasanya absen, karena 443 untuk https dan 80 untuk http tersirat.
  • Origin — skema, host, dan port bersama. Ini adalah unit yang menjadi dasar keamanan browser: kebijakan asal-sama, CORS, dan cakupan kuki semuanya membandingkan origin, bukan path.
  • Path — bagian setelah host dan sebelum ? atau # mana pun.
  • Kueri — pasangan kunci/nilai setelah ?, dipisah &.
  • Fragmen — segalanya setelah #. Secara unik, ini tak pernah dikirim ke server; ia ditangani sepenuhnya oleh browser.

Detail fragmen lebih penting daripada kedengarannya. Karena ia tak pernah meninggalkan browser, apa pun yang Anda taruh setelah sebuah # tak terlihat oleh log server — itulah sebabnya beberapa aplikasi satu-halaman secara historis memakainya untuk perutean, dan mengapa ia bukan tempat untuk dilihat saat men-debug sebuah permintaan yang tak pernah tiba.

Sebuah peringatan terakhir tentang apa yang tak dilakukan pengodean. Persen-pengodean membuat teks aman untuk diangkut di dalam sebuah URL; ia bukan sanitasi dan bukan kendali keamanan. Mengodekan sebuah nilai tak membuatnya aman untuk diinterpolasi ke dalam HTML, SQL, atau perintah shell, dan mendekode masukan tak tepercaya bisa mengungkap karakter — pemisah path, bita null — yang disembunyikan bentuk terkodekan. Validasi apa sebuah nilai itu, terpisah dari mengodekan bagaimana ia berkelana.

Alamat yang Anda ketik tak selalu alamat yang dikirim

Sebelum sebuah URL pergi ke mana pun ia dinormalisasi, dan penulisan ulang itu senyap. Alat ini menampilkan hasilnya kapan pun ia berbeda dari masukan, karena string itu — bukan yang Anda ketik — adalah yang menjangkau server dan yang muncul dalam sebuah log:

HTTPS://Example.COM:443\a\b     typed
https://example.com/a/b         sent

Empat aturan terpisah memicu di sana. Skema dan host dijadikan huruf kecil, karena tak satu pun peka besar-kecil. Port dibuang karena 443 adalah default untuk https. Garis miring terbalik menjadi garis miring maju, sebuah aturan kompatibilitas yang mengejutkan orang yang menulis path bergaya-Windows. Dan sebuah path kosong akan menjadi sebuah garis miring tunggal. Tak ada dari ini adalah sebuah galat, tetapi jika Anda membandingkan dua URL demi kesetaraan, atau mencocokkan satu terhadap sebuah daftar-izin, Anda harus membandingkan bentuk ternormalisasi atau Anda akan mendapatkan jawaban yang salah.

Sebuah nama host dengan karakter non-ASCII ditulis ulang pula, menjadi sebuah bentuk ASCII yang diawali xn--, disebut punycode. Alat menampilkan kedua arah: nama terbaca dan yang benar-benar berkelana. Ini layak dilihat ketimbang dilewati, karena dua nama Unicode berbeda bisa tampak identik di layar — sebuah "a" Latin dan sebuah "а" Kiril adalah karakter terpisah — sambil menghasilkan punycode yang sepenuhnya berbeda. Membandingkan bentuk ASCII adalah satu-satunya cara andal membedakan pasangan seperti itu.

Satu hal tak pernah dinormalisasi: sebuah parameter kueri yang berulang. Menulis ?tag=a&tag=b sepenuhnya sah, dan standar tak mengatakan apa artinya, jadi setiap tumpukan memilih jawabannya sendiri. PHP menyimpan nilai terakhir, Express mengumpulkannya ke dalam sebuah larik, banyak kerangka kerja dan URLSearchParams.get mengambil yang pertama. Alat menandai kunci yang berulang ketimbang mendaftarnya dua kali tanpa komentar, karena bug yang dihasilkan — sebuah nilai yang bekerja di satu layanan dan lenyap di yang lain — benar-benar sulit dilihat dengan membaca.

Pertanyaan yang sering diajukan

Apa perbedaan antara cakupan komponen dan URL penuh?
Cakupan komponen meng-escape pembatas / ? : @ & = + pula, yang tepat untuk satu nilai yang ditaruh di dalam sebuah URL. Cakupan URL penuh membiarkannya utuh karena di sana mereka memisahkan bagian-bagian alamat. Memakai cakupan komponen pada seluruh URL mengubah setiap garis miring menjadi %2F dan menghasilkan satu string tak terpakai.
Mengapa teks terdekode saya masih mengandung sebuah +?
Karena decodeURIComponent mengikuti RFC 3986, tempat + hanya sebuah plus. Pengiriman formulir dan kebanyakan string kueri memakai pengodean formulir, tempat + berarti sebuah spasi. Nyalakan "perlakukan + sebagai spasi" ketika teksnya berasal dari salah satunya.
Bagaimana saya mengodekan sebuah plus yang benar-benar sebuah plus?
Tulis ia sebagai %2B. Sebuah + harfiah dalam sebuah string kueri akan dibaca sebagai sebuah spasi oleh kebanyakan pengurai, jadi plus mana pun yang benar-benar bagian dari data Anda — dalam sebuah nomor telepon, misalnya — harus di-escape.
Apakah saya sebaiknya mengodekan seluruh URL atau hanya bagian-bagiannya?
Hanya bagian-bagiannya, dan lebih baik bukan dengan tangan: bangun alamat dengan URL dan URLSearchParams, yang menerapkan pengodean yang benar ke tiap komponen. Mengodekan sebuah URL yang telah dirakit setelahnya adalah dari mana kebanyakan bug pengodean-ganda datang.
Mengapa uraian menampilkan URL yang berbeda dari yang saya tempel?
Karena itulah yang dikirim. Sebuah URL dinormalisasi sebelum dipakai: skema dan host dijadikan huruf kecil, sebuah port default dibuang, garis miring terbalik menjadi garis miring, sebuah path kosong menjadi sebuah garis miring, dan sebuah host non-ASCII menjadi punycode. Jika Anda membandingkan URL atau mencocokkan terhadap sebuah daftar-izin, bandingkan bentuk ternormalisasi ini ketimbang teks mentahnya.
Mengapa tak ada uraian muncul untuk example.com/path?
Karena ia bukan URL absolut — ia tak punya skema, jadi tak ada host untuk dikenali. Alat tak akan menebak satu untuk Anda: example.com:8080 sudah menjadi URL absolut yang valid yang skemanya example.com dan path-nya 8080, jadi diam-diam memberi prefiks https:// bisa menghasilkan sebuah uraian yang tampak masuk akal dan salah. Tambahkan skemanya sendiri dan bagian-bagiannya muncul.
Apa itu pengodean ganda?
Mengodekan sebuah nilai yang sudah dikodekan, jadi sebuah %20 menjadi %2520 — tanda persennya sendiri di-escape. Ia biasanya muncul sebagai urutan %20 harfiah yang muncul dalam sebuah halaman. Dekode sekali dan periksa apakah Anda masih melihat escape; jika ya, ia dikodekan dua kali.
Apakah mengodekan sebuah nilai membuatnya aman?
Tidak. Persen-pengodean adalah tentang transport, bukan keamanan. Sebuah nilai terkodekan tetap apa pun ia tadinya, dan ia butuh validasi yang sama dan escape yang sesuai-konteks yang sama sebelum ia menjangkau HTML, SQL, atau sebuah shell.
Mengapa fragmen tak dikirim ke server?
Sesuai rancangan: segalanya setelah # ditangani browser sendiri dan tak pernah muncul dalam permintaan. Itulah sebabnya ia tak bisa dilihat di log server, dan mengapa ia secara historis dipakai untuk perutean sisi-klien.
Apakah yang saya tempel dikirim ke mana pun?
Tidak. Pengodean, pendekodean, dan uraian URL semuanya memakai fungsi bawaan browser sendiri dan berjalan sepenuhnya di perangkat Anda. Tidak ada yang Anda tempel meninggalkannya.