Codificar e decodificar URL
O Codificador e decodificador de URL aplica percent-encoding e decodifica texto no seu navegador. O modo importa mais do que parece: em uma query string, um espaço é +; em um path, é %20 — e decodificar o corpo de um formulário com o modo errado transforma “a + b” em “a b” sem nenhum erro.
Como funciona o Codificar e decodificar URL?
“URL encoding” nomeia três codificações diferentes, e escolher a errada produz um bug que nunca lança exceção.
Percent-encoding não é codificação de formulário
O percent-encoding do RFC 3986 escreve um espaço como %20. O formato application/x-www-form-urlencoded — o que uma query string e o corpo de um POST de formulário realmente usam — o escreve como +, o que significa que um sinal de mais literal precisa ser escrito %2B. Decodifique o corpo de um formulário com decodeURIComponent e o + permanece intacto, então a busca “a + b” chega como “a + b” quando a pessoa digitou um sinal de mais, e como “a+b” quando digitou espaços. Um dos dois está errado, e nenhum dos dois gera erro.
encodeURIComponent deixa passar cinco caracteres que o RFC reserva
!, ', (, ) e * são reservados pelo RFC 3986 e deixados de lado pelo encodeURIComponent. Normalmente é inofensivo; deixa de ser quando uma assinatura é calculada sobre o formulário codificado, e é por isso que toda biblioteca de AWS SigV4 e OAuth 1.0a traz seu próprio codificador. A opção strict os codifica.
Cada componente da URL tem suas próprias regras
Um path pode conter / ; um valor de query não pode conter um & sem codificação, senão ele se divide em dois parâmetros. Essa é a diferença entre o modo componente e o modo URL completa: o primeiro codifica tudo que não é unreserved, o segundo preserva os caracteres que dão a estrutura de uma URL. Codificar uma URL inteira com encodeURIComponent produz uma string que deixa de ser uma URL.
Codificação dupla, e como enxergá-la
%2520 é um espaço que passou duas vezes por um codificador: o % do %20 foi ele próprio codificado como %25. Para quem folheia um log de relance, ele se lê como “%20”, e no valor decodificado produz um %20 literal. A ferramenta conta quantas passadas de decodificação a entrada sobrevive, então uma camada extra indevida fica visível em vez de misteriosa.
Dividir uma URL usa o parser da plataforma
O detalhamento dos componentes vem da própria implementação de URL do navegador, e não de uma expressão regular, porque o parsing de URL tem casos extremos demais — userinfo, literais IPv6, portas padrão, hosts com percent-encoding —, e o algoritmo WHATWG que já existe na plataforma é ao mesmo tempo mais curto e mais correto do que qualquer padrão de expressão regular. Chaves de query duplicadas são preservadas na ordem, já que muitas APIs dão significado a elas.
Entrada
q=a + b
Codificado
component: q%3Da%20%2B%20b form: q%3Da+%2B+b
Quais opções e casos-limite o Codificar e decodificar URL suporta?
| Parâmetro | Tipo | Padrão | Comportamento e casos-limite |
|---|---|---|---|
| Componente | encodeURIComponent | padrão | Para um único valor de query ou um segmento de caminho. Codifica tudo, exceto A–Z a–z 0–9 - _ . ~ e os cinco caracteres abaixo. |
| URL completa | encodeURI | — | Para uma URL inteira. Mantém : / ? # [ ] @ ! $ & ' ( ) * + , ; = para que a URL continue sendo uma URL. Usar o modo componente aqui destrói a estrutura. |
| Formulário | x-www-form-urlencoded | — | Para uma query string ou um corpo POST. Espaço vira +, e um + literal vira %2B. Para decodificar corretamente, é preciso desfazer o + antes da decodificação por porcentagem; do contrário, um + literal vira espaço. |
| base64url | RFC 4648 §5 | — | O alfabeto base64 seguro para URL: - e _ em vez de + e /, sem padding. É o que os segmentos de JWT usam. |
| RFC 3986 estrito | booleano | desligado | Também codifica ! ' ( ) *, que encodeURIComponent deixa em paz. Necessário quando a forma codificada alimenta uma assinatura. |
| Codificar tudo | booleano | desligado | Codifica em porcentagem cada byte, inclusive os não reservados. Feio, válido e, às vezes, a única coisa que um gateway exigente aceita. |
| Conjunto de caracteres | UTF-8 | sempre | O que não é ASCII é codificado como seus bytes UTF-8, um %XX por byte, que é o que todo navegador e servidor atuais esperam. |
| Entrada malformada | notificada | com posição | decodeURIComponent lança um URIError puro e simples. Aqui, a sequência problemática é localizada e nomeada. |
Perguntas frequentes
Por que meu espaço virou um + em vez de %20?
Porque você está no modo formulário, que é o correto para uma query string ou para o corpo de um POST de formulário — esse formato define o espaço como +. Em um segmento de path ou em um fragmento, o espaço é %20 e o + é um sinal de mais literal. As duas codificações estão corretas; usar a errada para a posição é o que corrompe o valor.
encodeURI ou encodeURIComponent?
encodeURIComponent para uma parte isolada — um valor de query, um segmento de path, um fragmento. encodeURI para uma URL inteira que você quer que continue sendo uma URL. O teste é simples: se o texto que você está codificando contém caracteres estruturais (um ?, um &, um /) e você quer que eles continuem funcionando, use encodeURI; se você quer que eles virem dados, use encodeURIComponent.
O que é %2520 e como ele surgiu?
Um espaço, codificado duas vezes. A primeira passada produziu %20; a segunda codificou esse % como %25, resultando em %2520. Normalmente significa que um valor foi codificado pelo código da aplicação e depois de novo por um framework ou um proxy. O contador de profundidade acima mostra quantas passadas a sua entrada sobrevive, então você consegue saber se uma camada está sobrando.
Por que !'()* não é codificado?
O encodeURIComponent os deixa de propósito, mesmo que o RFC 3986 os reserve. Quase sempre é inofensivo — até o momento em que a string codificada vira a entrada de uma assinatura, onde quem assina e quem verifica precisam coincidir byte a byte. É por isso que AWS SigV4 e OAuth 1.0a especificam cada um o seu próprio codificador. Ative o modo strict se estiver nessa situação.
base64url é o mesmo que base64?
Mesmo algoritmo, alfabeto diferente. O base64 usa + e /, que são significativos em uma URL, então o base64url os troca por - e _ e descarta o preenchimento com =, que tem significado em uma query string. Um JWT são três segmentos base64url unidos por pontos, e é por isso que um JWT pode ser colado direto em uma URL e um blob base64 não.
Minha entrada é enviada?
Não. Codificar e decodificar são operações de string que rodam no seu navegador — abra o painel Network e observe enquanto você digita. Aqui isso importa porque as URLs que as pessoas precisam decodificar costumam ser URLs de callback assinadas, redirecionamentos OAuth e tokens de sessão, ou seja, credenciais em uma forma que parece inofensiva.