¿Cuándo se supone que debes usar escape en lugar de encodeURI / encodeURIComponent?

1392

Al codificar una cadena de consulta para enviarla a un servidor web: cuándo se usa escape()y cuándo se usa encodeURI()o encodeURIComponent():

Usar escape:

escape("% +&=");

O

use encodeURI () / encodeURIComponent ()

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

encodeURIComponent("var1=value1&var2=value2");
Adán
fuente
111
Vale la pena señalar que ese noencodeURIComponent("var1=value1&var2=value2") es el caso de uso típico. ¡Ese ejemplo codificará el y , que probablemente no sea lo que se pretendía! normalmente se aplica por separado solo al valor en cada par de valores clave (la parte después de cada uno ). =&encodeURIComponent=
Timothy Shields
3
¿Necesitas hacer algo con la llave? ¿Qué pasa si tiene un = en él? (¿es eso posible?)
Mala
3
@Mala Todavía soy nuevo en la programación web en general, pero lo que he usado en mi experiencia limitada es codificar la clave y el valor por separado, asegurando que el '=' permanezca: var params = encodeURIComponent(key) + '=' + encodeURIComponent(value);- Quizás alguien más conozca una mejor manera.
nedshares
1
@nedshares Estaba jugando con eso, pero por lo que puedo decir, la clave no parece estar codificada ... al menos no de la misma manera. ¿Quizás es contrario a las especificaciones tener un = en la clave?
Mala
1
También vale la pena señalar que las implementaciones recientes de JavaScript proporcionan las interfaces de nivel superior URL y URLSearchParams para manipular las URL y sus cadenas de consulta.
Bart Robinson

Respuestas:

1914

escapar()

¡No lo uses! escape()se define en la sección B.2.1.2 escape y el texto de introducción del Anexo B dice:

... Todas las características y comportamientos del lenguaje especificados en este anexo tienen una o más características indeseables y, en ausencia de uso heredado, se eliminarían de esta especificación. ...
... Los programadores no deben usar o asumir la existencia de estas características y comportamientos al escribir nuevo código ECMAScript ...

Comportamiento:

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

Los caracteres especiales se codifican con la excepción de: @ * _ + -. /

La forma hexadecimal para los caracteres, cuyo valor de unidad de código es 0xFF o menos, es una secuencia de escape de dos dígitos: %xx .

Para los caracteres con una unidad de código mayor, %uxxxxse utiliza el formato de cuatro dígitos . Esto no está permitido dentro de una cadena de consulta (como se define en RFC3986 ):

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

Un signo de porcentaje solo se permite si está seguido directamente por dos dígitos hexadecimales, porcentaje seguido por u no está permitido.

encodeURI ()

Use encodeURI cuando desee una URL que funcione. Haz esta llamada:

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

Llegar:

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

No llame a encodeURIComponent ya que destruiría la URL y devolvería

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

encodeURIComponent ()

Use encodeURIComponent cuando desee codificar el valor de un parámetro de URL.

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

Luego puede crear la URL que necesita:

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

Y obtendrá esta URL completa:

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

Tenga en cuenta que encodeURIComponent no escapa al 'personaje. Un error común es usarlo para crear atributos html como href='MyUrl', que podría sufrir un error de inyección. Si está construyendo html a partir de cadenas, use en "lugar de 'comillas de atributos o agregue una capa adicional de codificación (' puede codificarse como% 27).

Para obtener más información sobre este tipo de codificación, puede consultar: http://en.wikipedia.org/wiki/Percent-encoding

Arne Evertsson
fuente
31
@Francois, dependiendo del servidor receptor, puede no decodificar correctamente cómo escape codifica caracteres ASCII superiores o no ASCII como: â asêềểễếệ Por ejemplo, la clase FieldStorage de Python no decodificará la cadena anterior correctamente si se codifica bye escape.
Ray
22
@Francois escape () codifica los 128 caracteres ASCII inferiores, excepto letras, dígitos y *@-_+./ mientras que unescape () es el inverso de escape (). Por lo que puedo decir, son funciones heredadas diseñadas para codificar URL y solo se implementan para la compatibilidad con versiones anteriores. En general, no deben usarse a menos que interactúen con una aplicación / servicio web / etc. diseñado para ellos.
Anthony DiSanti
3
A menos que, por supuesto, intente pasar una URL como componente de URI, en cuyo caso llame a encodeURIComponent.
tom
44
¿Por qué no maneja la comilla simple?
Eric
11
@Eric No codifica comillas simples, porque las comillas simples son caracteres completamente válidos que se producen dentro de un URI ( RFC-3986 ). El problema ocurre cuando incrusta un URI dentro de HTML, donde la comilla simple no es un carácter válido. Entonces se deduce que los URI también deben estar "codificados en HTML" (que se reemplazarían 'por ') antes de colocarlos en un documento HTML.
Lee
441

La diferencia entre encodeURI()y encodeURIComponent()son exactamente 11 caracteres codificados por encodeURIComponent pero no por encodeURI:

Tabla con las diez diferencias entre encodeURI y encodeURIComponent

Generé esta tabla fácilmente con console.table en Google Chrome con este código:

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
fuente
¿No depende este navegador?
Pacerier
44
@bladnman encodeURI y encodeURIComponent deberían funcionar de esta manera en todos los principales navegadores. Puede probar el código anterior en Chrome y Firefox ya que ambos admiten console.table. En otros navegadores (incluidos Firefox y Chrome) puede usar el siguiente código: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
Quise decir @Pacerier :)
Johann Echavarria
@Pacerier debe ser idéntico en varios navegadores a menos que la especificación original sea demasiado ambigua ... también vea stackoverflow.com/questions/4407599/…
Christophe Roussy
2
¡NECESITO VOTAR ESTA VARIAS VECES! Lamentablemente, solo puede votar una vez.
Ramazan Polat
46

Encontré este artículo esclarecedor: Javascript Madness: Query String Parsing

Lo encontré cuando intentaba entender y por qué decodeURIComponent no estaba decodificando '+' correctamente. Aquí hay un extracto:

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
fuente
11
El artículo al que enlaza contiene muchas tonterías. Me parece que el propio autor no entendía para qué se usan correctamente las funciones ...
Christoph
2
@ Christoph Todo me parece razonable. En particular, estoy de acuerdo con él en que encodeURIparece que solo es útil en un caso marginal bastante oscuro y que realmente no necesita existir. Tengo algunas diferencias de opinión con él, pero no veo nada absolutamente falso o idiota allí. ¿Qué crees que es una tontería exactamente?
Mark Amery
1
El enctypeatributo del FORMelemento especifica el tipo de contenido utilizado para codificar el conjunto de datos del formulario para su envío al servidor. application / x-www-form-urlencoded Este es el tipo de contenido predeterminado. Los formularios enviados con este tipo de contenido deben codificarse de la siguiente manera: [...] los caracteres de espacio se reemplazan por `` + '' y los [...] caracteres no alfanuméricos se reemplazan por '% HH', [...] Ref: HTML4 Sepc
cychoi
2
encodeURIComponent ('A + B'). replace (/ \% 20 / g, '+') + '\ n' + decodeURIComponent ("A +% 2B + B" .replace (/ \ + / g, '% 20' ));
Zlatin Zlatev
39

encodeURIComponent no codifica -_.!~*'() , lo que causa problemas al publicar datos en php en una cadena xml.

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

Escape general con 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

Como puede ver, la comilla simple no está codificada. Para resolver el problema, creé dos funciones para resolver el problema en mi proyecto, para URL de codificación:

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");
}

Para decodificar 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
fuente
55
Tampoco hace el signo # (libra / hash / número), que es% 23.
xr280xr
1
@ xr280xr ¿Qué quieres decir? encodeURIComponent codifica # a% 23 (¿tal vez no lo hizo en 2014?)
David Balažic
38

encodeURI (): la función escape () es para el escape de JavaScript, no HTTP.

Daniel Papasian
fuente
Si tengo una URL como esta: var url = "http://kuler-api.adobe.com/rss/get.cfm?startIndex=0&itemsPerPage=20&timeSpan=0&listType=rating"... Y quiero acceder a ella a través de la API de Google Ajax, así: var gurl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q=" + url;... entonces tengo que usarla escape(url). encodeURI(url)no funciona con parámetros como ese parece.
Lance Pollard
15
deberías usar ecnodeURIComponent (url)
Ustaman Sangat
2
Todas las 3 funciones tienen sus problemas. Es mejor crear su propia función que hace el trabajo.
Jerry Joseph
17

Pequeña tabla de comparación 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
fuente
12

Recomiendo no usar uno de esos métodos tal como está. Escribe tu propia función que hace lo correcto.

MDN ha dado un buen ejemplo sobre la codificación de URL que se muestra a continuación.

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
fuente
1
qué gran respuesta (si es compatible a través de Chrome
Edge y Firefox
10

También recuerde que todos codifican diferentes conjuntos de caracteres y seleccione el que necesita de forma adecuada. encodeURI () codifica menos caracteres que encodeURIComponent (), que codifica menos caracteres (y también diferentes, al punto de dannyp) que escape ().

Pseudo masoquista
fuente
8

Con el fin de codificar, JavaScript ha dado tres funciones incorporadas:

  1. escape()- no codifica @*/+ Este método está en desuso después del ECMA 3, por lo que debe evitarse.

  2. encodeURI()- no codifica ~!@#$&*()=:/,;?+' Se supone que el URI es un URI completo, por lo que no codifica caracteres reservados que tienen un significado especial en el URI. Este método se utiliza cuando la intención es convertir la URL completa en lugar de un segmento especial de URL. Ejemplo - encodeURI('http://stackoverflow.com'); dará - http://stackoverflow.com

  3. encodeURIComponent()- no codifica - _ . ! ~ * ' ( ) Esta función codifica un componente de Identificador Uniforme de Recursos (URI) al reemplazar cada instancia de ciertos caracteres por una, dos, tres o cuatro secuencias de escape que representan la codificación UTF-8 del carácter. Este método debe usarse para convertir un componente de URL. Por ejemplo, se debe encodeURIComponent('http://stackoverflow.com'); agregar alguna entrada del usuario Ejemplo: dará - http% 3A% 2F% 2Fstackoverflow.com

Toda esta codificación se realiza en UTF 8, es decir, los caracteres se convertirán en formato UTF-8.

encodeURIComponent difiere de encodeURI en que codifica caracteres reservados y el signo de número # de encodeURI

Gaurav Tiwari
fuente
3

Descubrí que experimentar con los diversos métodos es un buen control de la cordura, incluso después de tener un buen manejo de cuáles son sus diversos usos y capacidades.

Con ese fin, he encontrado este sitio web extremadamente útil para confirmar mis sospechas de que estoy haciendo algo adecuadamente. También ha resultado útil para decodificar una cadena encodeURIComponent'ed que puede ser bastante difícil de interpretar. Un gran marcador para tener:

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

veeTrain
fuente
2

La respuesta aceptada es buena. Para extender en la última parte:

Tenga en cuenta que encodeURIComponent no escapa al carácter '. Un error común es usarlo para crear atributos html como href = 'MyUrl', que podría sufrir un error de inyección. Si está construyendo html a partir de cadenas, use "en lugar de 'para las comillas de atributos o agregue una capa adicional de codificación (' puede codificarse como% 27).

Si desea estar en el lado seguro, codifique el porcentaje de caracteres no reservados debe no reservados.

Puedes usar este método para escapar de ellos (fuente Mozilla )

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

// fixedEncodeURIComponent("'") --> "%27"
Miguel
fuente
2

Reescritura moderna de la respuesta 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
        )
)

O si puede usar una tabla, reemplácela console.logcon console.table(para la salida más bonita).

ryanpcmcquen
fuente
2

Inspirado por la mesa de Johann , he decidido extender la mesa. Quería ver qué caracteres ASCII se codifican.

captura de pantalla de console.table

La tabla muestra solo los caracteres codificados. Las celdas vacías significan que los caracteres originales y codificados son iguales.


Sólo para ser extra, estoy añadiendo otra mesa para urlencode()vs rawurlencode(). La única diferencia parece ser la codificación del carácter espacial.

captura de pantalla 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
fuente
1

Tengo esta función ...

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
fuente
44
@ChristianVielma escape () está en desuso pero nunca consulte w3schools.com. ver w3fools.com
Jerry Joseph
44
@Christian Vielma: algunos consideran que el material de referencia en W3Schools es menos controvertido y útil . No todos están de acuerdo en que W3Schools nunca debería ser referenciado.
DavidRR
2
W3Schools tiene una mala reputación. Claro que no siempre son precisos, pero de nuevo me he encontrado con muchas publicaciones en el blog que también son totalmente erróneas. Para mí, a veces es un gran punto de partida solo para aprender algo de la terminología y luego profundizar un poco más con otros recursos. Lo más importante es que un solo recurso nunca debe ser bíblico cuando se trata de este tipo de cosas.
ryandlf
Parece que @molokoloco escribió esta función como una alternativa a las versiones donde encodeURIno existe pero escapeexiste.
SOFe