Kapan Anda seharusnya menggunakan escape daripada encodeURI / encodeURIComponent?

1392

Saat menyandikan string kueri untuk dikirim ke server web - kapan Anda menggunakan escape()dan kapan Anda menggunakan encodeURI()atau encodeURIComponent():

Gunakan melarikan diri:

escape("% +&=");

ATAU

gunakan encodeURI () / encodeURIComponent ()

encodeURI("http://www.google.com?var1=value1&var2=value2");

encodeURIComponent("var1=value1&var2=value2");
Adam
sumber
111
Perlu ditunjukkan bahwa encodeURIComponent("var1=value1&var2=value2")ini bukan kasus penggunaan biasa. Contoh itu akan menyandikan =dan &, yang mungkin bukan yang dimaksudkan! encodeURIComponentbiasanya diterapkan secara terpisah untuk hanya nilai di setiap pasangan nilai kunci (bagian setelah masing-masing =).
Timothy Shields
3
apakah Anda perlu melakukan sesuatu terhadap kunci? Bagaimana jika ia memiliki = di dalamnya? (Apakah itu mungkin?)
Mala
3
@ Mala Saya masih baru untuk pemrograman web secara umum, tetapi apa yang saya gunakan dalam pengalaman terbatas saya adalah untuk menyandikan kunci dan nilai secara terpisah, memastikan '=' tetap: var params = encodeURIComponent(key) + '=' + encodeURIComponent(value);- Mungkin orang lain tahu cara yang lebih baik.
nedshares
1
@nedshares saya bermain dengan itu, tapi sejauh yang saya tahu kuncinya tampaknya tidak dikodekan ... setidaknya tidak dengan cara yang sama. Mungkin menentang spec untuk memiliki = di kunci?
Mala
1
Juga patut menunjukkan bahwa implementasi JavaScript terbaru menyediakan URL antarmuka tingkat tinggi dan URLSearchParams untuk memanipulasi URL dan string kueri mereka.
Bart Robinson

Jawaban:

1914

melarikan diri()

Jangan gunakan itu! escape()didefinisikan dalam bagian B.2.1.2 melarikan diri dan teks pengantar Lampiran B mengatakan:

... Semua fitur bahasa dan perilaku yang ditentukan dalam lampiran ini memiliki satu atau lebih karakteristik yang tidak diinginkan dan tanpa adanya penggunaan sebelumnya akan dihapus dari spesifikasi ini. ...
... Pemrogram tidak boleh menggunakan atau menganggap keberadaan fitur dan perilaku ini saat menulis kode skrip ECMAS baru ....

Tingkah laku:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/escape

Karakter khusus dikodekan dengan pengecualian: @ * _ + -. /

Bentuk heksadesimal untuk karakter, yang kode unit nilai adalah 0xFF atau kurang, adalah urutan escape dua-digit: %xx.

Untuk karakter dengan unit kode yang lebih besar, format empat digit %uxxxxdigunakan. Ini tidak diperbolehkan dalam string kueri (seperti yang didefinisikan dalam RFC3986 ):

query       = *( pchar / "/" / "?" )
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded   = "%" HEXDIG HEXDIG
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
              / "*" / "+" / "," / ";" / "="

Tanda persen hanya dibolehkan jika diikuti langsung oleh dua hexdigit, persen diikuti oleh utidak diizinkan.

encodeURI ()

Gunakan encodeURI saat Anda menginginkan URL yang berfungsi. Lakukan panggilan ini:

encodeURI("http://www.example.org/a file with spaces.html")

mendapatkan:

http://www.example.org/a%20file%20with%20spaces.html

Jangan panggil komponen encodeURIC karena akan menghancurkan URL dan kembali

http%3A%2F%2Fwww.example.org%2Fa%20file%20with%20spaces.html

komponen encodeURIC ()

Gunakan komponen encodeURIC ketika Anda ingin menyandikan nilai parameter URL.

var p1 = encodeURIComponent("http://example.org/?a=12&b=55")

Maka Anda dapat membuat URL yang Anda butuhkan:

var url = "http://example.net/?param1=" + p1 + "&param2=99";

Dan Anda akan mendapatkan URL lengkap ini:

http://example.net/?param1=http%3A%2F%2Fexample.org%2F%Ffa%3D12%26b%3D55&param2=99

Perhatikan bahwa komponen encodeURIC tidak lepas dari 'karakter. Bug yang umum adalah menggunakannya untuk membuat atribut html seperti href='MyUrl', yang dapat mengalami bug injeksi. Jika Anda membuat html dari string, gunakanlah "alih-alih 'untuk kutipan atribut, atau tambahkan lapisan pengkodean tambahan ( 'dapat dikodekan sebagai% 27).

Untuk informasi lebih lanjut tentang jenis pengkodean ini, Anda dapat memeriksa: http://en.wikipedia.org/wiki/Percent-encoding

Arne Evertsson
sumber
31
@ Francois, tergantung pada server penerima, mungkin tidak dapat memecahkan kode dengan benar bagaimana escape mengkodekan karakter ASCII atau non-ASCII yang lebih tinggi seperti: âầẩẫấậê, Misalnya, kelas FieldStorage Python tidak akan men-decode string di atas dengan benar jika dikodekan oleh melarikan diri.
Ray
22
@Francois escape () menyandikan 128 karakter ASCII yang lebih rendah kecuali huruf, angka, dan *@-_+./ sementara unescape () adalah kebalikan dari escape (). Sejauh yang saya tahu, itu adalah fungsi lama yang dirancang untuk menyandikan URL dan hanya diterapkan untuk kompatibilitas ke belakang. Umumnya, mereka tidak boleh digunakan kecuali berinteraksi dengan aplikasi / layanan web / dll yang dirancang untuk mereka.
Anthony DiSanti
3
Kecuali tentu saja Anda mencoba mengirimkan URL sebagai komponen URI di mana kompasen panggilan case encodeURIC.
tom
4
Mengapa itu tidak menangani kutipan tunggal?
Eric
11
@ Eric Ini tidak mengkodekan single-quote, karena single-quote adalah karakter yang benar-benar valid untuk muncul di dalam URI ( RFC-3986 ). Masalahnya terjadi ketika Anda menanamkan URI dalam HTML, di mana kutipan tunggal bukan karakter yang valid. Maka, kemudian, bahwa URI juga harus "HTML-encoded" (yang akan menggantikan 'dengan ') sebelum ditempatkan dalam dokumen HTML.
Lee
441

Perbedaan antara encodeURI()dan encodeURIComponent()persis 11 karakter yang dikodekan oleh encodeURICon tetapi tidak oleh encodeURI:

Tabel dengan sepuluh perbedaan antara komponen encodeURI dan encodeURIC

Saya membuat tabel ini dengan mudah dengan console.table di Google Chrome dengan kode ini:

var arr = [];
for(var i=0;i<256;i++) {
  var char=String.fromCharCode(i);
  if(encodeURI(char)!==encodeURIComponent(char)) {
    arr.push({
      character:char,
      encodeURI:encodeURI(char),
      encodeURIComponent:encodeURIComponent(char)
    });
  }
}
console.table(arr);

Johann Echavarria
sumber
Bukankah ini tergantung browser?
Pacerier
4
@bladnman encodeURI dan encodeURIComponent harus bekerja seperti ini di semua browser utama Anda dapat menguji kode di atas di Chrome dan Firefox karena keduanya mendukung console.table. Di peramban lain (termasuk Firefox dan Chrome) Anda dapat menggunakan kode berikut:var arr=[]; for(var i=0;i<256;i++){var char=String.fromCharCode(i); if(encodeURI(char)!==encodeURIComponent(char)) console.log("character: "+char + " | encodeURI: " +encodeURI(char) + " |encodeURIComponent: " + encodeURIComponent(char) ) }
Johann Echavarria
1
Maksud saya @Pacerier :)
Johann Echavarria
@Pacerier harus identik di berbagai browser kecuali spesifikasi aslinya terlalu ambigu ... juga lihat stackoverflow.com/questions/4407599/…
Christophe Roussy
2
SAYA PERLU MEMBUTUHKAN KALI BEBERAPA INI! Sayangnya hanya bisa mengungguli sekali.
Ramazan Polat
46

Saya menemukan artikel ini mencerahkan: Javascript Madness: Query String Parsing

Saya menemukannya ketika saya mencoba untuk menjelaskan mengapa komponen decodeURIC tidak mendekode '+' dengan benar. Berikut ini ekstraknya:

String:                         "A + B"
Expected Query String Encoding: "A+%2B+B"
escape("A + B") =               "A%20+%20B"     Wrong!
encodeURI("A + B") =            "A%20+%20B"     Wrong!
encodeURIComponent("A + B") =   "A%20%2B%20B"   Acceptable, but strange

Encoded String:                 "A+%2B+B"
Expected Decoding:              "A + B"
unescape("A+%2B+B") =           "A+++B"       Wrong!
decodeURI("A+%2B+B") =          "A+++B"       Wrong!
decodeURIComponent("A+%2B+B") = "A+++B"       Wrong!
Damien
sumber
11
Artikel yang Anda tautkan mengandung banyak omong kosong. Menurut saya, penulis sendiri tidak mengerti apa fungsi yang digunakan untuk ...
Christoph
2
@Christoph Semuanya terlihat masuk akal bagi saya. Secara khusus, saya setuju dengan dia yang encodeURIsepertinya hanya berguna dalam kasus tepi yang cukup jelas dan benar-benar tidak perlu ada. Saya memiliki beberapa perbedaan pendapat dengannya, tetapi saya tidak melihat ada sesuatu yang keliru atau bodoh di sana. Apa yang sebenarnya Anda pikirkan adalah omong kosong?
Mark Amery
1
The enctypeatribut dari FORMmenspesifikasikan elemen jenis konten yang digunakan untuk mengkodekan data formulir yang ditetapkan untuk penyerahan ke server. application / x-www-form-urlencoded Ini adalah tipe konten default. Formulir yang dikirimkan dengan tipe konten ini harus dikodekan sebagai berikut: [...] Karakter spasi diganti dengan `` + ', dan [...] Karakter non-alfanumerik diganti oleh `% HH', [...] Ref: HTML4 Sepc
cychoi
2
encodeURIComponent ('A + B'). ganti (/ \% 20 / g, '+') + '\ n' + komponen decodeURIC ("A +% 2B + B". ganti (/ \ + / g, '% 20' ));
Zlatin Zlatev
39

encodeURIComponent tidak menyandikan -_.!~*'(), menyebabkan masalah dalam memposting data ke php dalam xml string.

Sebagai contoh:
<xml><text x="100" y="150" value="It's a value with single quote" /> </xml>

Pelarian bersama encodeURI
%3Cxml%3E%3Ctext%20x=%22100%22%20y=%22150%22%20value=%22It's%20a%20value%20with%20single%20quote%22%20/%3E%20%3C/xml%3E

Anda bisa lihat, kutipan tunggal tidak dikodekan. Untuk mengatasi masalah, saya membuat dua fungsi untuk menyelesaikan masalah di proyek saya, untuk Encoding URL:

function encodeData(s:String):String{
    return encodeURIComponent(s).replace(/\-/g, "%2D").replace(/\_/g, "%5F").replace(/\./g, "%2E").replace(/\!/g, "%21").replace(/\~/g, "%7E").replace(/\*/g, "%2A").replace(/\'/g, "%27").replace(/\(/g, "%28").replace(/\)/g, "%29");
}

Untuk URL Dekode:

function decodeData(s:String):String{
    try{
        return decodeURIComponent(s.replace(/\%2D/g, "-").replace(/\%5F/g, "_").replace(/\%2E/g, ".").replace(/\%21/g, "!").replace(/\%7E/g, "~").replace(/\%2A/g, "*").replace(/\%27/g, "'").replace(/\%28/g, "(").replace(/\%29/g, ")"));
    }catch (e:Error) {
    }
    return "";
}
Kirankumar Sripati
sumber
5
Itu juga tidak melakukan tanda # (pound / hash / number), yaitu% 23.
xr280xr
1
@ xr280xr Apa maksudmu? encodeURIComponent tidak mengkodekan # ke% 23 (mungkin tidak pada tahun 2014?)
David Balažic
38

encodeURI () - fungsi escape () adalah untuk meloloskan javascript, bukan HTTP.

Daniel Papasian
sumber
Jika saya memiliki url seperti ini: var url = "http://kuler-api.adobe.com/rss/get.cfm?startIndex=0&itemsPerPage=20&timeSpan=0&listType=rating"... Dan saya ingin mengaksesnya melalui Google Ajax API, seperti ini: var gurl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q=" + url;... maka saya harus menggunakan escape(url). encodeURI(url)sepertinya tidak berfungsi dengan parameter seperti itu.
Lance Pollard
15
Anda harus menggunakan komponen ecnodeURIC (url)
Ustaman Sangat
2
Semua 3 fungsi memiliki masalah mereka. Lebih baik untuk membuat fungsi Anda sendiri yang melakukan pekerjaan.
Jerry Joseph
17

Tabel perbandingan kecil Java vs JavaScript vs PHP.

1. Java URLEncoder.encode (using UTF8 charset)
2. JavaScript encodeURIComponent
3. JavaScript escape
4. PHP urlencode
5. PHP rawurlencode

char   JAVA JavaScript --PHP---
[ ]     +    %20  %20  +    %20
[!]     %21  !    %21  %21  %21
[*]     *    *    *    %2A  %2A
[']     %27  '    %27  %27  %27 
[(]     %28  (    %28  %28  %28
[)]     %29  )    %29  %29  %29
[;]     %3B  %3B  %3B  %3B  %3B
[:]     %3A  %3A  %3A  %3A  %3A
[@]     %40  %40  @    %40  %40
[&]     %26  %26  %26  %26  %26
[=]     %3D  %3D  %3D  %3D  %3D
[+]     %2B  %2B  +    %2B  %2B
[$]     %24  %24  %24  %24  %24
[,]     %2C  %2C  %2C  %2C  %2C
[/]     %2F  %2F  /    %2F  %2F
[?]     %3F  %3F  %3F  %3F  %3F
[#]     %23  %23  %23  %23  %23
[[]     %5B  %5B  %5B  %5B  %5B
[]]     %5D  %5D  %5D  %5D  %5D
----------------------------------------
[~]     %7E  ~    %7E  %7E  ~
[-]     -    -    -    -    -
[_]     _    _    _    _    _
[%]     %25  %25  %25  %25  %25
[\]     %5C  %5C  %5C  %5C  %5C
----------------------------------------
char  -JAVA-  --JavaScript--  -----PHP------
[ä]   %C3%A4  %C3%A4  %E4     %C3%A4  %C3%A4
[ф]   %D1%84  %D1%84  %u0444  %D1%84  %D1%84
30 th
sumber
12

Saya sarankan untuk tidak menggunakan salah satu metode tersebut apa adanya. Tulis fungsi Anda sendiri yang melakukan hal yang benar.

MDN telah memberikan contoh yang baik tentang penyandian url yang ditunjukkan di bawah ini.

var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''" + encodeRFC5987ValueChars(fileName);

console.log(header); 
// logs "Content-Disposition: attachment; filename*=UTF-8''my%20file%282%29.txt"


function encodeRFC5987ValueChars (str) {
    return encodeURIComponent(str).
        // Note that although RFC3986 reserves "!", RFC5987 does not,
        // so we do not need to escape it
        replace(/['()]/g, escape). // i.e., %27 %28 %29
        replace(/\*/g, '%2A').
            // The following are not required for percent-encoding per RFC5987, 
            //  so we can allow for a little better readability over the wire: |`^
            replace(/%(?:7C|60|5E)/g, unescape);
}

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

Jerry Joseph
sumber
1
jawaban yang bagus (jika kompatibel dengan chrome edge dan firefox tanpa membuat kesalahan)
yan bellavance
10

Juga ingat bahwa mereka semua menyandikan serangkaian karakter yang berbeda, dan pilih yang Anda butuhkan dengan tepat. encodeURI () mengkodekan karakter lebih sedikit daripada encodeURIComponent (), yang mengkodekan lebih sedikit (dan juga berbeda, ke titik dannyp's) karakter daripada escape ().

Masokis semu
sumber
8

Untuk tujuan pengkodean javascript telah memberikan tiga fungsi bawaan -

  1. escape()- tidak menyandikan @*/+ Metode ini sudah usang setelah ECMA 3 sehingga harus dihindari.

  2. encodeURI()- tidak mengkodekan ~!@#$&*()=:/,;?+' Ini mengasumsikan bahwa URI adalah URI yang lengkap, jadi jangan menyandikan karakter yang dipesan yang memiliki arti khusus dalam URI. Metode ini digunakan ketika tujuannya adalah untuk mengkonversi URL lengkap alih-alih beberapa segmen URL khusus. Contoh - encodeURI('http://stackoverflow.com'); akan memberikan - http://stackoverflow.com

  3. encodeURIComponent()- tidak mengkodekan - _ . ! ~ * ' ( ) Fungsi ini mengkodekan komponen Uniform Resource Identifier (URI) dengan mengganti setiap instance karakter tertentu dengan satu, dua, tiga, atau empat sekuens escape yang mewakili pengkodean karakter UTF-8. Metode ini harus digunakan untuk mengonversi komponen URL. Misalnya beberapa input pengguna perlu ditambahkan. Contoh - encodeURIComponent('http://stackoverflow.com'); akan memberikan - http% 3A% 2F% 2Fstackoverflow.com

Semua pengkodean ini dilakukan dalam UTF 8 yaitu karakter akan dikonversi dalam format UTF-8.

encodeURIComponent berbeda dari encodeURI dalam encodeUR karakter yang dilindungi undang-undang dan tanda Nomor # dari encodeURI

Gaurav Tiwari
sumber
3

Saya telah menemukan bahwa bereksperimen dengan berbagai metode adalah pemeriksaan kewarasan yang baik bahkan setelah memiliki pegangan yang baik tentang berbagai kegunaan dan kemampuan mereka.

Menjelang akhir itu saya menemukan situs web ini sangat berguna untuk mengkonfirmasi kecurigaan saya bahwa saya melakukan sesuatu dengan tepat. Ini juga terbukti berguna untuk mendekode string yang dikompilasi oleh encodeURIC yang agak sulit ditafsirkan. Bookmark yang bagus untuk dimiliki:

http://www.the-art-of-web.com/javascript/escape/

veTrain
sumber
2

Jawaban yang diterima bagus. Untuk memperluas pada bagian terakhir:

Perhatikan bahwa komponen encodeURIC tidak lepas dari karakter '. Bug umum adalah menggunakannya untuk membuat atribut html seperti href = 'MyUrl', yang dapat mengalami bug injeksi. Jika Anda membuat html dari string, gunakan "bukan 'untuk kutipan atribut, atau tambahkan lapisan pengkodean tambahan (' dapat dikodekan sebagai% 27).

Jika Anda ingin berada di sisi yang aman, persen pengkodean karakter tanpa syarat harus dikodekan juga.

Anda dapat menggunakan metode ini untuk menghindarinya (sumber Mozilla )

function fixedEncodeURIComponent(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}

// fixedEncodeURIComponent("'") --> "%27"
Michael
sumber
2

Penulisan ulang modern jawaban @ johann-echavarria:

console.log(
    Array(256)
        .fill()
        .map((ignore, i) => String.fromCharCode(i))
        .filter(
            (char) =>
                encodeURI(char) !== encodeURIComponent(char)
                    ? {
                          character: char,
                          encodeURI: encodeURI(char),
                          encodeURIComponent: encodeURIComponent(char)
                      }
                    : false
        )
)

Atau jika Anda bisa menggunakan tabel, ganti console.logdengan console.table(untuk hasil yang lebih cantik).

ryanpcmcquen
sumber
2

Terinspirasi oleh meja Johann , saya telah memutuskan untuk memperpanjang meja. Saya ingin melihat karakter ASCII mana yang dikodekan.

tangkapan layar console.table

Tabel hanya menunjukkan karakter yang disandikan. Sel kosong berarti bahwa karakter asli dan yang disandikan adalah sama.


Hanya untuk menjadi ekstra, saya menambahkan meja lain untuk urlencode()vs rawurlencode(). Satu-satunya perbedaan tampaknya adalah pengkodean karakter ruang.

tangkapan layar console.table

<script>
<?php
$ascii = str_split(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 1);
$encoded = [];
foreach ($ascii as $char) {
    $obj = ["char" => $char];
    if ($char != urlencode($char))
        $obj["urlencode"] = urlencode($char);
    if ($char != rawurlencode($char))
        $obj["rawurlencode"] = rawurlencode($char);
    if (isset($obj["rawurlencode"]) || isset($obj["rawurlencode"]))
        $encoded[] = $obj;
}
echo "var encoded = " . json_encode($encoded) . ";";
?>
console.table(encoded);
</script>
akinuri
sumber
1

Saya memiliki fungsi ini ...

var escapeURIparam = function(url) {
    if (encodeURIComponent) url = encodeURIComponent(url);
    else if (encodeURI) url = encodeURI(url);
    else url = escape(url);
    url = url.replace(/\+/g, '%2B'); // Force the replacement of "+"
    return url;
};
molokoloco
sumber
4
@ChristianVielma escape () sudah usang tetapi tidak pernah merujuk w3schools.com. lihat w3fools.com
Jerry Joseph
4
@Christian Vielma - Beberapa menemukan bahan referensi di W3Schools menjadi kurang kontroversial dan bermanfaat . Tidak semua orang setuju bahwa W3Schools tidak boleh dirujuk.
DavidRR
2
W3Schools mendapatkan rap yang buruk. Tentu mereka tidak selalu akurat, tetapi sekali lagi saya telah menemukan banyak posting blog yang benar-benar salah juga. Bagi saya kadang-kadang titik awal yang bagus hanya untuk mempelajari beberapa terminologi dan kemudian saya menyelam sedikit lebih dalam dengan sumber daya lainnya. Yang paling penting adalah bahwa satu sumber daya tidak boleh alkitabiah dalam hal-hal semacam ini.
ryandlf
Tampaknya @molokoloco menulis fungsi ini sebagai fallback ke versi yang encodeURItidak ada tetapi escapeada.
SOFe