Quando você deve usar escape em vez de encodeURI / encodeURIComponent?

1392

Ao codificar uma sequência de consulta a ser enviada para um servidor da Web - quando você usa escape()e quando usa encodeURI()ou encodeURIComponent():

Use escape:

escape("% +&=");

OU

use encodeURI () / encodeURIComponent ()

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

encodeURIComponent("var1=value1&var2=value2");
Adão
fonte
111
Vale ressaltar que esse nãoencodeURIComponent("var1=value1&var2=value2") é o caso de uso típico. Esse exemplo codificará o e , o que provavelmente não é o que se pretendia! normalmente é aplicado separadamente apenas ao valor em cada par de valores-chave (a parte após cada ). =&encodeURIComponent=
Timothy Shields
3
você precisa fazer alguma coisa com a chave? E se tiver um = nele? (que é mesmo possível?)
Mala
3
@ Malala Eu ainda sou novo em programação web em geral, mas o que eu usei em minha experiência limitada é codificar a chave e o valor separadamente, garantindo que o '=' permaneça: var params = encodeURIComponent(key) + '=' + encodeURIComponent(value);- Talvez alguém conheça uma maneira melhor.
Nedshares
1
@nedshares Eu estava brincando com isso, mas até onde eu sei, a chave não parece estar codificada ... pelo menos não da mesma maneira. Talvez seja contra a especificação ter um = na chave?
Mala1
1
Também vale ressaltar que as implementações recentes do JavaScript fornecem as interfaces de nível superior URL e URLSearchParams para manipular URLs e suas cadeias de consulta.
Bart Robinson

Respostas:

1914

fuga()

Não use! escape()é definido na seção B.2.1.2, escape e o texto de introdução do anexo B diz:

... Todos os recursos e comportamentos de linguagem especificados neste anexo têm uma ou mais características indesejáveis ​​e, na ausência de uso legado, seriam removidos desta especificação. Os
programadores não devem usar ou assumir a existência desses recursos e comportamentos ao escrever o novo código ECMAScript.

Comportamento:

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

Caracteres especiais são codificados, com exceção de: @ * _ + -. /

A forma hexadecimal para caracteres, cujo valor de unidade de código é 0xFF ou menos, é uma sequência de escape de dois dígitos: %xx.

Para caracteres com uma unidade de código maior, %uxxxxé utilizado o formato de quatro dígitos . Isso não é permitido em uma sequência de consultas (conforme definido no RFC3986 ):

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

Um sinal de porcentagem é permitido apenas se for diretamente seguido por dois hexadígitos, por cento seguido por unão é permitido.

encodeURI ()

Use encodeURI quando quiser um URL de trabalho. Faça esta ligação:

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

para obter:

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

Não chame encodeURIComponent, pois isso destruiria o URL e retornaria

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

encodeURIComponent ()

Use encodeURIComponent quando desejar codificar o valor de um parâmetro de URL.

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

Em seguida, você pode criar o URL necessário:

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

E você obterá este URL completo:

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

Observe que encodeURIComponent não escapa ao 'caractere. Um bug comum é usá-lo para criar atributos html como href='MyUrl', que podem sofrer um bug de injeção. Se você estiver construindo html a partir de strings, use em "vez de 'para aspas de atributo ou adicione uma camada extra de codificação ( 'pode ser codificada como% 27).

Para mais informações sobre este tipo de codificação, você pode verificar: http://en.wikipedia.org/wiki/Percent-encoding

Arne Evertsson
fonte
31
@Francois, dependendo do servidor de destino, ele pode não decodificar adequadamente como escape codifica caracteres ASCII ou não ASCII superiores, como: Por exemplo, a classe FieldStorage do Python não decodificará a string acima se codificada por escape.
Raio
22
@Francois escape () codifica os 128 caracteres ASCII inferiores, exceto letras, dígitos e *@-_+./, enquanto unescape () é o inverso de escape (). Tanto quanto posso dizer, são funções herdadas projetadas para codificar URLs e ainda são implementadas apenas para compatibilidade com versões anteriores. Geralmente, eles não devem ser usados, a menos que interajam com um aplicativo / serviço da web / etc projetado para eles.
Anthony DiSanti
3
A menos que você esteja tentando transmitir um URL como um componente URI, nesse caso, chame encodeURIComponent.
tom
4
Por que ele não lida com aspas simples?
Eric
11
@ Eric Não codifica aspas simples, porque aspas simples é um caractere completamente válido para ocorrer dentro de um URI ( RFC-3986 ). O problema ocorre quando você incorpora um URI no HTML, onde aspas simples não são um caractere válido. Daqui resulta que os URIs também devem ser "codificados em HTML" (que seriam substituídos 'por ') antes de serem colocados em um documento HTML.
26414 Lee
441

A diferença entre encodeURI()e encodeURIComponent()são exatamente 11 caracteres codificados por encodeURIComponent, mas não por encodeURI:

Tabela com as dez diferenças entre encodeURI e encodeURIComponent

Gerei esta tabela facilmente com console.table no Google Chrome com 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
fonte
Este navegador não é dependente?
Pacerier 27/09/14
4
@bladnman encodeURI e encodeURIComponent devem funcionar dessa maneira em todos os principais navegadores. Você pode testar o código acima no Chrome e Firefox, pois ambos suportam console.table. Em outros navegadores (incluindo Firefox e Chrome), você pode usar o seguinte 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
Eu quis dizer @Pacerier :)
Johann Echavarria
@Pacerier deve ser idêntica em vários navegadores, a menos que a especificação original é muito ambígua ... veja também stackoverflow.com/questions/4407599/...
Christophe Roussy
2
EU PRECISO ATUALIZAR ESTA VÁRIAS VEZES! Infelizmente, você pode apenas votar uma vez.
Ramazan Polat
46

Eu achei este artigo esclarecedor: Loucura de Javascript: Análise de String de Consulta

Encontrei-o quando estava tentando entender por que decodeURIComponent não estava decodificando '+' corretamente. Aqui está um extrato:

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
fonte
11
O artigo ao qual você vincula contém muitas bobagens. Parece-me que o próprio autor não entendeu para que as funções são usadas corretamente ...
Christoph
2
@Christoph Tudo parece razoável para mim. Em particular, concordo com ele, que encodeURIparece útil apenas em um caso bastante obscuro e realmente não precisa existir. Tenho algumas diferenças de opinião com ele, mas não vejo nada totalmente falso ou idiota lá. O que exatamente você acha que não faz sentido?
Mark Amery
1
O enctypeatributo do FORMelemento especifica o tipo de conteúdo usado para codificar o conjunto de dados do formulário para envio ao servidor. application / x-www-form-urlencoded Esse é o tipo de conteúdo padrão. Os formulários enviados com esse tipo de conteúdo devem ser codificados da seguinte forma: [...] caracteres de espaço são substituídos por `` + '', [...] e caracteres não alfanuméricos são substituídos por `% HH ', [...] Ref: HTML4 Sepc
cychoi
2
encodeURIComponent ('A + B'). replace (/ \% 20 / g, '+') + '\ n' + decodeURIComponent ("A +% 2B + B". substitua (/ \ + / g, '% 20' ));
Zlatin Zlatev
39

encodeURIComponent não codifica -_.!~*'(), causando problemas ao publicar dados no php na string xml.

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

Fuga geral com 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

Você pode ver, as aspas simples não são codificadas. Para resolver o problema, criei duas funções para resolver o problema no meu projeto, para URL de codificação:

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 URL de decodificação:

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
fonte
5
Ele também não exibe o sinal # (libra / hash / número), que é% 23.
Xr280xr
1
@ xr280xr Como assim? encodeURIComponent codifica # para% 23 (talvez não o tenha sido em 2014?) #
18760 David Balažic 15/10
38

encodeURI () - a função escape () é para escape de javascript, não HTTP.

Daniel Papasian
fonte
Se eu tenho um URL como este: var url = "http://kuler-api.adobe.com/rss/get.cfm?startIndex=0&itemsPerPage=20&timeSpan=0&listType=rating"... E eu quero acessá-lo através da API do Google Ajax, assim: var gurl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q=" + url;... então eu tenho que usar escape(url). encodeURI(url)não funciona com parâmetros como o que parece.
Lance Pollard
15
u deve usar ecnodeURIComponent (url)
Ustaman Sangat
2
Todas as 3 funções têm seus problemas. É melhor criar sua própria função que faz o trabalho.
21714 Jerry Joseph
17

Pequena tabela de comparação 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ª
fonte
12

Eu recomendo não usar um desses métodos como está. Escreva sua própria função que faça a coisa certa.

O MDN deu um bom exemplo da codificação de URL mostrada abaixo.

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
fonte
1
o que é uma grande resposta (se seu compatível em cromo ponta e firefox enquanto não cometer nenhum erro)
yan Bellavance
10

Lembre-se também de que todos eles codificam conjuntos diferentes de caracteres e selecione o que você precisa adequadamente. encodeURI () codifica menos caracteres que encodeURIComponent (), que codifica menos (e também diferente, para o ponto de dannyp) caracteres do que escape ().

Pseudo-masoquista
fonte
8

Para fins de codificação, o javascript forneceu três funções embutidas -

  1. escape()- não codifica @*/+ Este método foi descontinuado após o ECMA 3, portanto deve ser evitado.

  2. encodeURI()- não codifica ~!@#$&*()=:/,;?+' Pressupõe que o URI é um URI completo, portanto, não codifica caracteres reservados que tenham um significado especial no URI. Este método é usado quando a intenção é converter o URL completo em vez de algum segmento especial do URL. Exemplo - encodeURI('http://stackoverflow.com'); dará - http://stackoverflow.com

  3. encodeURIComponent()- não codifica - _ . ! ~ * ' ( ) Essa função codifica um componente URI (Uniform Resource Identifier) ​​substituindo cada instância de determinados caracteres por uma, duas, três ou quatro seqüências de escape representando a codificação UTF-8 do caractere. Este método deve ser usado para converter um componente da URL. Por exemplo, algumas entradas do usuário precisam ser anexadas Exemplo - encodeURIComponent('http://stackoverflow.com'); irá fornecer - http% 3A% 2F% 2Fstackoverflow.com

Toda essa codificação é realizada em UTF 8, ou seja, os caracteres serão convertidos no formato UTF-8.

encodeURIComponent difere de encodeURI, na medida em que codifica caracteres reservados e o sinal numérico # de encodeURI

Gaurav Tiwari
fonte
3

Descobri que experimentar os vários métodos é uma boa verificação de sanidade, mesmo depois de ter uma boa noção de quais são seus vários usos e capacidades.

Para esse fim, achei este site extremamente útil para confirmar minhas suspeitas de que estou fazendo algo apropriadamente. Também se provou útil para decodificar uma string codificadaURIComponent'ed, o que pode ser bastante difícil de interpretar. Um ótimo marcador para ter:

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

veeTrain
fonte
2

A resposta aceita é boa. Para estender a última parte:

Observe que encodeURIComponent não escapa ao caractere '. Um erro comum é usá-lo para criar atributos html, como href = 'MyUrl', que pode sofrer um erro de injeção. Se você estiver construindo html a partir de strings, use "em vez de 'para aspas de atributo ou adicione uma camada extra de codificação (' pode ser codificada como% 27).

Se você deseja estar do lado seguro, a porcentagem de caracteres não reservados que também estão em reserva.

Você pode usar esse método para escapar deles (fonte Mozilla )

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

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

Reescrita moderna da resposta 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, se você puder usar uma tabela, substitua console.logpor console.table(para a saída mais bonita).

ryanpcmcquen
fonte
2

Inspirado na mesa de Johann , decidi estender a mesa. Eu queria ver quais caracteres ASCII são codificados.

captura de tela do console.table

A tabela mostra apenas os caracteres codificados. Células vazias significam que os caracteres originais e codificados são os mesmos.


Só para ficar extra, eu estou adicionando outra mesa para urlencode()vs rawurlencode(). A única diferença parece ser a codificação do caractere de espaço.

captura de tela do 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
fonte
1

Eu tenho essa função ...

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
fonte
4
O @ChristianVielma escape () está obsoleto, mas nunca se refere a w3schools.com. Veja w3fools.com
Jerry Joseph
4
@Christian Vielma - Alguns encontrar o material de referência em W3Schools ser menos controverso e útil . Nem todo mundo concorda que o W3Schools nunca deve ser mencionado.
DavidRR
2
O W3Schools tem uma má reputação. Claro que eles nem sempre são precisos, mas, novamente, me deparei com muitos posts que também estão errados. Para mim, às vezes é um ótimo ponto de partida apenas para aprender um pouco da terminologia e, em seguida, mergulho um pouco mais fundo com outros recursos. O mais importante é que um único recurso nunca deve ser bíblico quando se trata desse tipo de coisa.
ryandlf
Parece que o @molokoloco escreveu essa função como um substituto para versões em encodeURIque não existe, mas escapeexiste.
SOFe 23/10