Por que URLs precisam de codificação
Uma URL é composta por caracteres — e nem todos são "seguros" para uso direto. As URLs são transmitidas pela internet através de sistemas que podem interpretar certos caracteres como tendo um significado especial (como ? para query strings, & para separar parâmetros ou # para identificadores de fragmento). Outros caracteres podem ser não-ASCII (como letras chinesas ou árabes), e alguns podem ser corrompidos por infraestruturas HTTP mais antigas.
A codificação de URL (oficialmente chamada de percent-encoding) resolve isso substituindo os caracteres não seguros por % seguido da representação hexadecimal de dois dígitos do valor de byte do caractere.
Um espaço (0x20) → %20
Um arroba (0x40) → %40
Uma barra (0x2F) → %2F
O Padrão RFC
A codificação de URL é definida na RFC 3986 (Uniform Resource Identifiers). De acordo com esse padrão:
Caracteres não reservados — podem ser usados com segurança em qualquer parte de uma URL sem codificação:
- A–Z, a–z, 0–9
-,_,.,~
Caracteres reservados — têm significado especial em URIs e devem ser percent-codificados quando usados como dados:
: / ? # [ ] @ ! $ & ' ( ) * + , ; =
Todo o resto — incluindo espaços, caracteres não-ASCII e caracteres como ", <, >, {, } — deve ser percent-codificado.
Percent-encoding na Prática
Codificando um espaço
O caractere espaço (U+0020) é codificado como %20. Você também pode ver + sendo usado em vez de %20 em query strings — isso vem do padrão de codificação de formulários HTML (application/x-www-form-urlencoded), onde espaços são codificados como +. Os dois são distintos:
%20— percent-encoding RFC 3986 (espaços em caminhos e cabeçalhos)+— codificação de formulário HTML (espaços em query strings)
Ao decodificar, sempre saiba qual convenção se aplica para evitar bugs.
Caracteres não-ASCII
Caracteres não-ASCII são primeiro codificados em UTF-8, depois cada byte é percent-codificado:
Caractere chinês 中 (U+4E2D)
Bytes UTF-8: 0xE4 0xB8 0xAD
Percent-encoded: %E4%B8%AD
Em português, a palavra ação contém o caractere ã (U+00E3) que é codificado como %C3%A3 em UTF-8, e o ç (U+00E7) como %C3%A7.
Funções de Codificação em JavaScript
O JavaScript fornece várias funções integradas para codificação de URL:
encodeURI()
Codifica uma URI completa — projetada para codificar uma URL inteira enquanto preserva sua estrutura. Não codifica caracteres que fazem parte da sintaxe URI: ; , / ? : @ & = + $ #.
encodeURI("https://example.com/search?q=olá mundo&lang=português")
// "https://example.com/search?q=ol%C3%A1%20mundo&lang=portugu%C3%AAs"
encodeURIComponent()
Codifica um componente de URI — projetada para codificar valores individuais como valores de parâmetros de query. Codifica tudo exceto A–Z a–z 0–9 - _ . ! ~ * ' ( ).
encodeURIComponent("olá mundo & mais")
// "ol%C3%A1%20mundo%20%26%20mais"
encodeURIComponent("https://example.com")
// "https%3A%2F%2Fexample.com"
Quando usar cada uma
| Cenário | Função |
|---|---|
| Codificar uma URL inteira | encodeURI() |
| Codificar um valor de parâmetro de query | encodeURIComponent() |
| Codificar um segmento de caminho | encodeURIComponent() |
| Codificar uma URL para embutir em outra URL | encodeURIComponent() |
As funções de decodificação complementares
decodeURI(encodedURI)
decodeURIComponent(encodedComponent)
Nunca use as funções obsoletas escape() e unescape() — elas tratam caracteres não-ASCII de forma diferente e produzem resultados incorretos.
Armadilhas e Problemas Comuns
Dupla codificação
Um bug frequente é codificar uma string que já está codificada:
encodeURIComponent(encodeURIComponent("olá mundo"))
// "ol%25C3%25A1%2520mundo"
// %25 é a codificação de %, então %20 se tornou %2520
Sempre verifique se o valor já está codificado antes de codificá-lo.
A armadilha do + vs %20
Se você decodificar com decodeURIComponent uma query string que usa + para espaços, o + não será decodificado como espaço — você precisa substituir + por %20 antes, ou usar a API URLSearchParams:
new URLSearchParams("q=ola+mundo").get("q")
// "ola mundo" ✓
decodeURIComponent("ola+mundo")
// "ola+mundo" ✗ — ainda tem um sinal de mais literal
Identificadores de fragmento
O caractere # nas URLs marca o início de um identificador de fragmento (para âncoras dentro da página). Se você tiver um # nos dados, ele deve ser codificado como %23, caso contrário o navegador tratará tudo depois dele como um fragmento.
Nomes de Domínio Internacionalizados (IDN)
Nomes de domínio com caracteres não-ASCII (como bücher.de) usam codificação Punycode, não percent-encoding. Os navegadores convertem IDNs para Punycode internamente: bücher.de → xn--bcher-kva.de.
Referência de Estrutura de URL
Uma URL possui os seguintes componentes (conforme RFC 3986):
scheme://userinfo@host:port/path?query#fragment
| Componente | Exemplo | Regras de codificação |
|---|---|---|
| Scheme | https | Letras, dígitos, +, -, . |
| Host | example.com | Labels de domínio + pontos |
| Port | 8080 | Apenas dígitos |
| Path | /search/results | Codificado com %XX exceto não-reservados + :@!$&'()*+,;= |
| Query | q=ola+mundo | + para espaços em dados de formulário, %20 em geral |
| Fragment | #section-2 | Não enviado ao servidor; apenas navegador |
Considerações do Lado do Servidor
Normalização de URLs
Os servidores devem normalizar URLs antes de processá-las — por exemplo, tratar %41 (que decodifica para A) da mesma forma que A. Porém, alguns caracteres têm significados diferentes codificados vs não codificados: / vs %2F em caminhos — muitos servidores web os tratam diferentemente por razões de segurança (proteção contra path traversal).
Injeção SQL via Parâmetros de URL
Sempre sanitize e valide os parâmetros de URL antes de usá-los em consultas de banco de dados, mesmo após a decodificação. A codificação de URL não é uma barreira de segurança.
Ferramentas e APIs
A API URL do Navegador
Navegadores modernos e Node.js fornecem a API URL para trabalhar com URLs de forma estruturada:
const url = new URL("https://example.com/search?q=olá mundo&page=1");
console.log(url.searchParams.get("q")); // "olá mundo" (decodificado automaticamente)
url.searchParams.set("q", "novo valor & especial");
console.log(url.href);
// https://example.com/search?q=novo+valor+%26+especial&page=1
A API URL trata a codificação/decodificação de forma transparente, sendo geralmente a abordagem preferida em vez de chamadas manuais a encodeURIComponent.
Resumo
A codificação de URL é um conceito fundamental que todo desenvolvedor web encontra diariamente, muitas vezes sem perceber. Os pontos-chave a lembrar:
- O percent-encoding (
%XX) é o mecanismo padrão para codificar caracteres não seguros em URIs. - Use
encodeURIComponent()para valores individuais eencodeURI()para URLs completas. - Esteja ciente da distinção entre
+e%20nas query strings. - Evite dupla codificação — verifique se uma string já está codificada antes de codificá-la.
- Prefira as APIs modernas
URLeURLSearchParamspara trabalhar com URLs de forma programática.