Kiedy należy użyć klawisza Escape zamiast encodeURI / encodeURIComponent?

1392

Podczas kodowania ciągu zapytania, który ma zostać wysłany na serwer sieciowy - kiedy używasz escape()i kiedy używasz encodeURI()lub encodeURIComponent():

Użyj ucieczki:

escape("% +&=");

LUB

użyj encodeURI () / encodeURIComponent ()

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

encodeURIComponent("var1=value1&var2=value2");
Adam
źródło
111
Warto zauważyć, że nieencodeURIComponent("var1=value1&var2=value2") jest to typowy przypadek użycia. Ten przykład zakoduje i , co prawdopodobnie nie jest zamierzone! jest zwykle stosowany osobno tylko do wartości w każdej parze wartości klucza (część po każdej ). =&encodeURIComponent=
Timothy Shields
3
czy musisz coś zrobić z kluczem? Co jeśli ma w nim =? (czy to w ogóle możliwe?)
Mala
3
@Mala Wciąż jestem nowy w programowaniu stron internetowych, ale w moim ograniczonym doświadczeniu wykorzystałem osobne kodowanie klucza i wartości, upewniając się, że „=” pozostaje: var params = encodeURIComponent(key) + '=' + encodeURIComponent(value);- Może ktoś inny zna lepszy sposób.
nedshares
1
@nedshares Bawiłem się tym, ale o ile wiem, klucz nie wydaje się być zakodowany ... przynajmniej nie w ten sam sposób. Może to wbrew specyfikacji mieć = w kluczu?
Mala
1
Warto również zauważyć, że ostatnie implementacje JavaScript zapewniają interfejsy wyższego poziomu URL i URLSearchParams do manipulowania adresami URL i ich ciągami zapytań.
Bart Robinson,

Odpowiedzi:

1914

ucieczka()

Nie używaj tego! escape()jest zdefiniowany w sekcji B.2.1.2 ucieczka, a tekst wprowadzający do załącznika B mówi:

... Wszystkie funkcje językowe i zachowania określone w tym załączniku mają jedną lub więcej niepożądanych cech, a przy braku starszego użycia zostałyby usunięte z tej specyfikacji. ...
... Programiści nie powinni używać ani zakładać istnienia tych funkcji i zachowań podczas pisania nowego kodu ECMAScript ....

Zachowanie:

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

Znaki specjalne są kodowane z wyjątkiem: @ * _ + -. /

Formularz szesnastkowy dla bohaterów, których kod jest jednostka wartość 0xFF lub mniej, to sekwencja ucieczki dwucyfrowa: %xx.

W przypadku znaków o większej jednostce kodu stosuje się czterocyfrowy format %uxxxx. Jest to niedozwolone w ciągu zapytania (zgodnie z definicją w RFC3986 ):

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

Znak procentu jest dozwolony tylko wtedy, gdy bezpośrednio po nim następują dwie cyfry szesnastkowe, a następnie procent unie jest dozwolony.

encodeURI ()

Użyj encodeURI, jeśli potrzebujesz działającego adresu URL. Zadzwoń:

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

uzyskać:

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

Nie wywołuj encodeURIComponent, ponieważ zniszczyłby adres URL i zwrócił

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

encodeURIComponent ()

Użyj encodeURIComponent, jeśli chcesz zakodować wartość parametru URL.

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

Następnie możesz utworzyć potrzebny adres URL:

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

Otrzymasz ten pełny adres URL:

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

Zauważ, że encodeURIComponent nie zmienia 'znaku. Częstym błędem jest używanie go do tworzenia atrybutów HTML, takich jak href='MyUrl', które mogą cierpieć z powodu błędu wstrzykiwania. Jeśli konstruujesz HTML z ciągów znaków, użyj "zamiast 'cudzysłowów atrybutów lub dodaj dodatkową warstwę kodowania ( 'może być zakodowana jako% 27).

Aby uzyskać więcej informacji na temat tego rodzaju kodowania, możesz sprawdzić: http://en.wikipedia.org/wiki/Percent-encoding

Arne Evertsson
źródło
31
@Francois, w zależności od serwera odbierającego, może nieprawidłowo dekodować sposób, w jaki kod ucieczki koduje górne znaki ASCII lub znaki inne niż ASCII, takie jak: ầẩẫấậ Na przykład klasa FieldStorage Pythona nie dekoduje poprawnie powyższego łańcucha, jeśli zostanie zakodowana bye escape.
Ray
22
@Francois escape () koduje niższe 128 znaków ASCII oprócz liter, cyfr i *@-_+./, podczas gdy unescape () jest odwrotnością escape (). O ile wiem, są to starsze funkcje przeznaczone do kodowania adresów URL i nadal są implementowane tylko w celu zapewnienia zgodności z poprzednimi wersjami. Zasadniczo nie należy ich używać, chyba że wchodzi w interakcję z zaprojektowaną dla nich aplikacją / usługą internetową / etc.
Anthony DiSanti,
3
O ile oczywiście nie próbujesz przekazać adresu URL jako komponentu URI, w takim przypadku wywołaj encodeURIComponent.
tom
4
Dlaczego nie obsługuje pojedynczego cytatu?
Eric
11
@Eric Nie koduje pojedynczego cudzysłowu, ponieważ pojedynczy cudzysłów jest całkowicie poprawnym znakiem występującym w URI ( RFC-3986 ). Problem występuje, gdy osadzisz identyfikator URI w kodzie HTML, w którym pojedynczy cudzysłów nie jest prawidłowym znakiem. Wynika z tego, że identyfikatory URI powinny również zostać „zakodowane w formacie HTML” (który zastąpi 'je ') przed umieszczeniem w dokumencie HTML.
Lee
441

Różnica między encodeURI()i encodeURIComponent()wynosi dokładnie 11 znaków zakodowanych przez encodeURIComponent, ale nie przez encodeURI:

Tabela z dziesięcioma różnicami między encodeURI i encodeURIComponent

Wygenerowałem tę tabelę z łatwością za pomocą console.table w Google Chrome z tym kodem:

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
źródło
Czy ta przeglądarka nie jest zależna?
Pacerier
4
@bladnman encodeURI i encodeURIComponent powinny działać w ten sposób we wszystkich głównych przeglądarkach. Możesz przetestować powyższy kod w Chrome i Firefox jako oba obsługujące plik console.table. W innych przeglądarkach (w tym Firefox i Chrome) możesz użyć następującego kodu: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
Miałem na myśli @Pacerier :)
Johann Echavarria
@Pacerier powinien być identyczny w różnych przeglądarkach, chyba że oryginalna specyfikacja jest zbyt dwuznaczna ... zobacz także stackoverflow.com/questions/4407599/…
Christophe Roussy
2
POTRZEBUJĘ TE GODZINY! Niestety można głosować tylko raz.
Ramazan Polat
46

Znalazłem ten artykuł pouczający: JavaScript Madness: Query String Parsing

Znalazłem to, gdy próbowałem podkreślić i dlaczego decodeURIComponent nie dekodował poprawnie „+”. Oto wyciąg:

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
źródło
11
Artykuł, do którego linkujesz, zawiera wiele bzdur. Wydaje mi się, że sam autor nie rozumiał, do jakich funkcji są właściwie wykorzystywane ...
Christoph
2
@Christoph Wszystko dla mnie wygląda rozsądnie. W szczególności zgadzam się z nim, który encodeURIwydaje się przydatny tylko w dość niejasnym przypadku i naprawdę nie musi istnieć. Mam z nim pewne różnice zdań, ale nie widzę w tym nic wprost fałszywego lub idiotycznego. Co dokładnie uważasz za nonsens?
Mark Amery
1
enctypeAtrybutem FORMOkreśla element typ zawartości używany do kodowania zestawu danych formularza do składania do serwera. application / x-www-form-urlencoded Jest to domyślny typ zawartości. Formularze przesłane z tym typem treści muszą być kodowane w następujący sposób: [...] Znaki spacji są zastępowane przez `` + ', a [...] Znaki niealfanumeryczne są zastępowane przez `% HH', [...] Ref: HTML4 Sepc
tychoi
2
encodeURIComponent („A + B”). replace (/ \% 20 / g, „+”) + „\ n” + decodeURIComponent („A +% 2B + B” .replace (/ \ + / g, „% 20”) ));
Zlatin Zlatev
39

encodeURIComponent nie koduje -_.!~*'(), co powoduje problem z wysyłaniem danych do php w ciągu xml.

Na przykład:
<xml><text x="100" y="150" value="It's a value with single quote" /> </xml>

Ogólna ucieczka z 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

Widzisz, pojedynczy cytat nie jest zakodowany. Aby rozwiązać problem, stworzyłem dwie funkcje rozwiązania problemu w moim projekcie, dla Kodowania adresu 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");
}

W przypadku dekodowania adresu URL:

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
źródło
5
Nie robi też znaku # (funt / skrót / liczba), który wynosi% 23.
xr280xr
1
@ xr280xr Co masz na myśli? encodeURIComponent koduje # do% 23 (może nie w 2014 roku?)
David Balažic
38

encodeURI () - funkcja escape () służy do zmiany znaczenia javascript, a nie HTTP.

Daniel Papasian
źródło
Jeśli mam taki adres URL: var url = "http://kuler-api.adobe.com/rss/get.cfm?startIndex=0&itemsPerPage=20&timeSpan=0&listType=rating"... I chcę uzyskać do niego dostęp za pośrednictwem interfejsu API Google Ajax, w ten sposób: var gurl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q=" + url;... to muszę go użyć escape(url). encodeURI(url)nie działa z takimi parametrami, jak się wydaje.
Lance Pollard,
15
powinieneś użyć ecnodeURIComponent (url)
Ustaman Sangat
2
Wszystkie 3 funkcje mają swoje problemy. Lepiej jest stworzyć własną funkcję, która spełnia swoje zadanie.
Jerry Joseph
17

Mała tabela porównawcza 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
30th
źródło
12

Zalecam, aby nie używać takiej metody, jaka jest. Napisz swoją własną funkcję, która działa poprawnie.

MDN podał dobry przykład kodowania adresów URL pokazany poniżej.

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
źródło
1
co za świetna odpowiedź (jeśli jest kompatybilna z chromowanymi krawędziami i
firefoxem
10

Pamiętaj również, że wszystkie kodują różne zestawy znaków i odpowiednio wybierz ten, którego potrzebujesz. encodeURI () koduje mniej znaków niż encodeURIComponent (), który koduje mniej (a także inaczej niż w punkcie Dannypa) znaków niż escape ().

Pseudo masochista
źródło
8

W celu kodowania javascript ma trzy wbudowane funkcje -

  1. escape()- nie koduje @*/+ Ta metoda jest przestarzała po ECMA 3, dlatego należy jej unikać.

  2. encodeURI()- nie koduje ~!@#$&*()=:/,;?+' Zakłada, że ​​URI jest pełnym URI, więc nie koduje znaków zastrzeżonych, które mają specjalne znaczenie w URI. Ta metoda jest używana, gdy celem jest konwersja pełnego adresu URL zamiast jakiegoś specjalnego segmentu adresu URL. Przykład - encodeURI('http://stackoverflow.com'); da - http://stackoverflow.com

  3. encodeURIComponent()- nie koduje - _ . ! ~ * ' ( ) Ta funkcja koduje składnik Uniform Resource Identifier (URI), zastępując każdą instancję niektórych znaków jedną, dwiema, trzema lub czterema sekwencjami ucieczki reprezentującymi kodowanie UTF-8 znaku. Tej metody należy użyć do konwersji składnika adresu URL. Na przykład należy dołączyć dane wejściowe użytkownika Przykład - encodeURIComponent('http://stackoverflow.com'); da - http% 3A% 2F% 2Fstackoverflow.com

Całe to kodowanie odbywa się w UTF 8, tzn. Znaki zostaną przekonwertowane w formacie UTF-8.

encodeURIComponent różni się od encodeURI tym, że koduje znaki zastrzeżone i znak numeryczny # encodeURI

Gaurav Tiwari
źródło
3

Przekonałem się, że eksperymentowanie z różnymi metodami jest dobrym sprawdzianem zdrowia psychicznego, nawet jeśli dobrze rozumiesz, jakie są ich różne zastosowania i możliwości.

W tym celu uważam, że ta strona internetowa jest niezwykle przydatna do potwierdzenia moich podejrzeń, że robię coś odpowiednio. Okazało się także przydatne do dekodowania łańcucha znaków encodeURIComponent, którego interpretacja może być trudna. Świetna zakładka do:

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

veeTrain
źródło
2

Przyjęta odpowiedź jest dobra. Aby rozszerzyć ostatnią część:

Zauważ, że encodeURIComponent nie zmienia znaku „. Częstym błędem jest używanie go do tworzenia atrybutów HTML, takich jak href = 'MyUrl', które mogą zostać uszkodzone przez błąd wstrzykiwania. Jeśli konstruujesz HTML z ciągów, użyj „zamiast” dla cudzysłowów atrybutów lub dodaj dodatkową warstwę kodowania („może być zakodowany jako% 27).

Jeśli chcesz być bezpieczny, należy również zakodować procent kodowania niezarezerwowanych znaków .

Możesz użyć tej metody, aby je uciec (źródło Mozilla )

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

// fixedEncodeURIComponent("'") --> "%27"
Michał
źródło
2

Współczesne przepisanie odpowiedzi @ 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
        )
)

Lub jeśli można użyć tabeli, należy wymienić console.logz console.table(na wyjściu ładniejszej).

ryanpcmcquen
źródło
2

Zainspirowany stołem Johanna postanowiłem go przedłużyć. Chciałem zobaczyć, które znaki ASCII zostaną zakodowane.

zrzut ekranu z pliku console.table

Tabela pokazuje tylko zakodowane znaki. Puste komórki oznaczają, że oryginalne i zakodowane znaki są takie same.


Wystarczy być ekstra, Dodaję kolejny tabeli urlencode()kontra rawurlencode(). Jedyną różnicą wydaje się być kodowanie znaku spacji.

zrzut ekranu z pliku 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
źródło
1

Mam tę funkcję ...

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
źródło
4
@ChristianVielma escape () jest przestarzałe, ale nigdy nie polecaj w3schools.com. patrz w3fools.com
Jerry Joseph
4
@Christian Vielma - Niektórzy uważają, że materiał odniesienia w W3Schools być mniej kontrowersyjne i użyteczne . Nie wszyscy zgadzają się, że nie należy nigdy odwoływać się do W3Schools.
DavidRR,
2
W3Schools ma zły rap. Jasne, że nie zawsze są one dokładne, ale znowu natknąłem się na wiele postów na blogu, które również są całkowicie błędne. Czasami jest to dla mnie świetny punkt wyjścia do nauki terminologii, a potem nurkuję trochę głębiej z innymi zasobami. Najważniejsze jest to, że pojedynczy zasób nigdy nie powinien być biblijny, jeśli chodzi o tego rodzaju rzeczy.
ryandlf
Wygląda na to, że @molokoloco napisał tę funkcję jako powrót do wersji, w których encodeURInie istnieje, ale escapeistnieje.
SOFe