Quand êtes-vous censé utiliser escape au lieu d'encodeURI / encodeURIComponent?

1392

Lors du codage d'une chaîne de requête à envoyer à un serveur Web - quand utilisez-vous escape()et quand utilisez-vous encodeURI()ou encodeURIComponent():

Utilisez escape:

escape("% +&=");

OU

utilisez encodeURI () / encodeURIComponent ()

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

encodeURIComponent("var1=value1&var2=value2");
Adam
la source
111
Il convient de souligner que ce encodeURIComponent("var1=value1&var2=value2")n'est pas le cas d'utilisation typique. Cet exemple encodera le =et &, ce qui n'est probablement pas ce qui était prévu! encodeURIComponentest généralement appliqué séparément à la seule valeur de chaque paire de valeurs clés (la partie après chaque =).
Timothy Shields
3
avez-vous besoin de faire quoi que ce soit à la clé? Et si elle contient un =? (est-ce même possible?)
Mala
3
@Mala Je suis encore nouveau dans la programmation Web en général, mais ce que j'ai utilisé dans mon expérience limitée est d'encoder la clé et la valeur séparément, en veillant à ce que le '=' reste: var params = encodeURIComponent(key) + '=' + encodeURIComponent(value);- Peut-être que quelqu'un d'autre connaît mieux.
nedshares
1
@nedshares Je jouais avec ça, mais pour autant que je sache, la clé ne semble pas être encodée ... du moins pas de la même manière. C'est peut-être contraire aux spécifications d'avoir un = dans la clé?
Mala
1
Il convient également de souligner que les récentes implémentations JavaScript fournissent les interfaces de niveau supérieur URL et URLSearchParams pour manipuler les URL et leurs chaînes de requête.
Bart Robinson

Réponses:

1914

échapper()

Ne l'utilisez pas! escape()est défini dans la section B.2.1.2 escape et le texte d'introduction de l'annexe B dit:

... Toutes les fonctionnalités et comportements linguistiques spécifiés dans la présente annexe ont une ou plusieurs caractéristiques indésirables et, en l'absence d'utilisation héritée, seraient supprimés de cette spécification. ...
... Les programmeurs ne doivent pas utiliser ou supposer l'existence de ces fonctionnalités et comportements lors de l'écriture de nouveau code ECMAScript ....

Comportement:

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

Les caractères spéciaux sont codés à l'exception de: @ * _ + -. /

La forme hexadécimale de caractères, dont la valeur unitaire du code est 0xFF ou moins, est une séquence d'échappement à deux chiffres: %xx.

Pour les caractères avec une unité de code plus grande, le format à quatre chiffres %uxxxxest utilisé. Ceci n'est pas autorisé dans une chaîne de requête (comme défini dans RFC3986 ):

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

Un signe de pourcentage n'est autorisé que s'il est directement suivi de deux chiffres hexadécimaux, le pourcentage suivi de un'est pas autorisé.

encodeURI ()

Utilisez encodeURI lorsque vous voulez une URL de travail. Faites cet appel:

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

obtenir:

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

N'appelez pas encodeURIComponent car cela détruirait l'URL et retournerait

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

encodeURIComponent ()

Utilisez encodeURIComponent lorsque vous souhaitez coder la valeur d'un paramètre d'URL.

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

Ensuite, vous pouvez créer l'URL dont vous avez besoin:

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

Et vous obtiendrez cette URL complète:

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

Notez que encodeURIComponent n'échappe pas au 'caractère. Un bogue courant consiste à l'utiliser pour créer des attributs html tels que href='MyUrl', qui pourraient subir un bogue d'injection. Si vous construisez du code HTML à partir de chaînes, utilisez "au lieu de 'pour les guillemets d'attributs ou ajoutez une couche d'encodage supplémentaire ( 'peut être encodé en tant que% 27).

Pour plus d'informations sur ce type d'encodage, vous pouvez consulter: http://en.wikipedia.org/wiki/Percent-encoding

Arne Evertsson
la source
31
@Francois, selon le serveur récepteur, il peut ne pas décoder correctement la façon dont escape encode les caractères ASCII ou non ASCII supérieurs tels que: • Par exemple, la classe FieldStorage de Python ne décode pas correctement la chaîne ci-dessus si elle est encodée bye escape.
Ray
22
@Francois escape () code les 128 caractères ASCII inférieurs sauf les lettres, les chiffres et *@-_+./ tandis que unescape () est l'inverse de escape (). Pour autant que je sache, ce sont des fonctions héritées conçues pour encoder des URL et ne sont toujours implémentées que pour une compatibilité descendante. En règle générale, ils ne doivent pas être utilisés sauf s'ils interagissent avec une application / un service Web / etc. conçu pour eux.
Anthony DiSanti
3
À moins bien sûr que vous essayiez de passer une URL en tant que composant URI, auquel cas appelez encodeURIComponent.
tom
4
Pourquoi ne gère-t-il pas le devis unique?
Eric
11
@Eric Il n'encode pas de guillemets simples, car les guillemets simples sont des caractères complètement valides qui se produisent dans un URI ( RFC-3986 ). Le problème se produit lorsque vous incorporez un URI dans HTML, où le guillemet simple n'est pas un caractère valide. Il s'ensuit alors que les URI doivent également être "codés en HTML" (qui les remplaceraient 'par ') avant d'être placés dans un document HTML.
Lee
441

La différence entre encodeURI()et encodeURIComponent()est exactement de 11 caractères encodés par encodeURIComponent mais pas par encodeURI:

Tableau avec les dix différences entre encodeURI et encodeURIComponent

J'ai généré ce tableau facilement avec console.table dans Google Chrome avec ce code:

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
la source
Ce navigateur n'est-il pas dépendant?
Pacerier
4
@bladnman encodeURI et encodeURIComponent devraient fonctionner de cette façon dans tous les principaux navigateurs. Vous pouvez tester le code ci-dessus dans Chrome et Firefox en tant que support console.table. Dans d'autres navigateurs (dont Firefox et Chrome), vous pouvez utiliser le code suivant: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
Je voulais dire @Pacerier :)
Johann Echavarria
@Pacerier devrait être identique dans les différents navigateurs à moins que la spécification d'origine ne soit trop ambiguë ... voir aussi stackoverflow.com/questions/4407599/…
Christophe Roussy
2
JE DOIS METTRE À JOUR CETTE FOIS PLUSIEURS! Malheureusement, ne peut voter qu'une seule fois.
Ramazan Polat
46

J'ai trouvé cet article instructif: Javascript Madness: Query String Parsing

Je l'ai trouvé lorsque j'essayais de comprendre pourquoi decodeURIComponent ne décodait pas correctement «+». En voici un extrait:

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
la source
11
L'article auquel vous créez un lien contient beaucoup de bêtises. Il me semble que l'auteur lui-même n'a pas compris à quoi servent les fonctions ...
Christoph
2
@Christoph Tout me semble raisonnable. En particulier, je suis d'accord avec lui qui encodeURIsemble que cela n'est utile que dans un cas de bord assez obscur et n'a vraiment pas besoin d'exister. J'ai des divergences d'opinion avec lui, mais je n'y vois absolument rien de faux ou d'idiot. Que pensez-vous exactement est un non-sens?
Mark Amery
1
L' enctypeattribut de l' FORMélément spécifie le type de contenu utilisé pour coder l'ensemble de données de formulaire à soumettre au serveur. application / x-www-form-urlencoded Il s'agit du type de contenu par défaut. Les formulaires soumis avec ce type de contenu doivent être codés comme suit: [...] Les caractères d'espace sont remplacés par `` + '', et [...] Les caractères non alphanumériques sont remplacés par `% HH ', [...] Ref: HTML4 Sepc
cychoi
2
encodeURIComponent ('A + B'). replace (/ \% 20 / g, '+') + '\ n' + decodeURIComponent ("A +% 2B + B" .replace (/ \ + / g, '% 20' ));
Zlatin Zlatev
39

encodeURIComponent n'encode pas -_.!~*'(), ce qui provoque un problème de publication des données sur php dans la chaîne xml.

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

Évasion générale avec 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

Vous voyez, les guillemets simples ne sont pas encodés. Pour résoudre le problème, j'ai créé deux fonctions pour résoudre le problème dans mon projet, pour 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");
}

Pour décoder l'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
la source
5
Il ne fait pas non plus le signe # (dièse / hachage / nombre), qui est% 23.
xr280xr
1
@ xr280xr Que voulez-vous dire? encodeURIComponent encode # en% 23 (peut-être pas en 2014?)
David Balažic
38

encodeURI () - la fonction escape () est pour l'échappement javascript, pas HTTP.

Daniel Papasian
la source
Si j'ai une URL comme celle-ci: var url = "http://kuler-api.adobe.com/rss/get.cfm?startIndex=0&itemsPerPage=20&timeSpan=0&listType=rating"... Et je veux y accéder via l'API Google Ajax, comme ceci: var gurl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q=" + url;... alors je dois utiliser escape(url). encodeURI(url)ne fonctionne pas avec des paramètres comme il semble.
Lance Pollard
15
vous devez utiliser ecnodeURIComponent (url)
Ustaman Sangat
2
Toutes les 3 fonctions ont leurs problèmes. Il vaut mieux créer votre propre fonction qui fait le travail.
Jerry Joseph
17

Petit tableau de comparaison 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
30thh
la source
12

Je recommande de ne pas utiliser l'une de ces méthodes telles quelles. Écrivez votre propre fonction qui fait la bonne chose.

MDN a donné un bon exemple sur le codage d'URL ci-dessous.

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
la source
1
quelle bonne réponse (si elle est compatible avec chrome edge et firefox sans faire d'erreurs)
yan bellavance
10

N'oubliez pas non plus qu'ils encodent tous différents ensembles de caractères et sélectionnez celui dont vous avez besoin de manière appropriée. encodeURI () encode moins de caractères que encodeURIComponent (), qui encode moins de caractères (et aussi différents, au point de Dannyp) que escape ().

Pseudo masochiste
la source
8

Aux fins de l'encodage javascript a donné trois fonctions intégrées -

  1. escape()- n'encode pas @*/+ Cette méthode est déconseillée après l'ECMA 3, elle doit donc être évitée.

  2. encodeURI()- n'encode pas ~!@#$&*()=:/,;?+' Il suppose que l'URI est un URI complet, donc n'encode pas les caractères réservés qui ont une signification spéciale dans l'URI. Cette méthode est utilisée lorsque l'intention est de convertir l'URL complète au lieu d'un segment spécial d'URL. Exemple - encodeURI('http://stackoverflow.com'); donnera - http://stackoverflow.com

  3. encodeURIComponent()- ne pas coder - _ . ! ~ * ' ( ) Cette fonction code un composant URI (Uniform Resource Identifier) ​​en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant le codage UTF-8 du caractère. Cette méthode doit être utilisée pour convertir un composant d'URL. Par exemple, certaines entrées utilisateur doivent être ajoutées Exemple - encodeURIComponent('http://stackoverflow.com'); donnera - http% 3A% 2F% 2Fstackoverflow.com

Tout cet encodage est effectué en UTF 8 c'est-à-dire que les caractères seront convertis au format UTF-8.

encodeURIComponent diffère de encodeURI en ce qu'il encode les caractères réservés et le numéro de signe # d'encodeURI

Gaurav Tiwari
la source
3

J'ai trouvé qu'expérimenter avec les différentes méthodes est une bonne vérification de la santé mentale même après avoir une bonne idée de leurs différentes utilisations et capacités.

À cette fin, j'ai trouvé ce site Web extrêmement utile pour confirmer mes soupçons que je fais quelque chose de manière appropriée. Il s'est également avéré utile pour décoder une chaîne encodéeURIComponent'ed qui peut être assez difficile à interpréter. Un excellent marque-page pour avoir:

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

veeTrain
la source
2

La réponse acceptée est bonne. Pour étendre sur la dernière partie:

Notez que encodeURIComponent n'échappe pas au caractère '. Un bogue courant consiste à l'utiliser pour créer des attributs html tels que href = 'MyUrl', qui pourraient subir un bogue d'injection. Si vous construisez du code HTML à partir de chaînes, utilisez "au lieu de" pour les guillemets d'attributs, ou ajoutez une couche d'encodage supplémentaire ("peut être encodé en tant que% 27).

Si vous voulez être du bon côté, le pourcentage d'encodage des caractères non réservés doit également être encodé.

Vous pouvez utiliser cette méthode pour leur échapper (source Mozilla )

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

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

Réécriture moderne de la réponse de @ 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
        )
)

Ou si vous pouvez utiliser un tableau, remplacez-le console.logpar console.table(pour une sortie plus jolie).

ryanpcmcquen
la source
2

Inspiré par la table de Johann , j'ai décidé d'étendre la table. Je voulais voir quels caractères ASCII étaient encodés.

capture d'écran de console.table

Le tableau affiche uniquement les caractères codés. Les cellules vides signifient que l'original et les caractères codés sont identiques.


Juste pour être encore plus, j'ajoute une autre table pour urlencode()vs rawurlencode(). La seule différence semble être l'encodage du caractère spatial.

capture d'écran de 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
la source
1

J'ai cette fonction ...

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
la source
4
@ChristianVielma escape () est déconseillé mais ne réfère jamais à w3schools.com. voir w3fools.com
Jerry Joseph
4
@Christian Vielma - Certains trouvent que le matériel de référence à W3Schools est moins controversé et utile . Tout le monde n'est pas d'accord pour que W3Schools ne soit jamais référencé.
DavidRR
2
W3Schools obtient un mauvais rap. Bien sûr, ils ne sont pas toujours exacts, mais là encore, je suis tombé sur de nombreux articles de blog qui sont tout aussi faux. Pour moi, c'est parfois un excellent point de départ juste pour apprendre une partie de la terminologie, puis je plonge un peu plus profondément avec d'autres ressources. Le plus important est qu'une seule ressource ne doit jamais être biblique quand il s'agit de ce genre de choses.
ryandlf
Il semble que @molokoloco ait écrit cette fonction comme une solution de rechange aux versions où elle encodeURIn'existe pas mais escapeexiste.
SOFe