Aposto que você já teve um bug onde uma URL com espaços ou caracteres especiais quebrou alguma coisa. Talvez uma consulta de busca com & causou um comportamento estranho. Ou você viu %20 em uma URL e ficou se perguntando o que era. Vamos esclarecer tudo isso.
Por que URLs precisam de codificação
URLs só podem conter um conjunto limitado de caracteres. A especificação RFC 3986 define os caracteres "não reservados" que são sempre seguros: A-Z, a-z, 0-9, -, _, . e ~. Todo o resto — espaços, &, =, ?, caracteres não-ASCII como ñ ou 日本語 — precisa ser codificado com porcentagem.
Como a codificação por porcentagem funciona
É bem direto: pegue o valor em bytes UTF-8 do caractere e represente cada byte como % seguido de dois dígitos hexadecimais.
Exemplos:
- Espaço →
%20 &→%26=→%3Dé→%C3%A9(dois bytes em UTF-8)日→%E6%97%A5(três bytes em UTF-8)
Então Hello World vira Hello%20World no caminho de uma URL.
O bug número 1: Codificação dupla
Esse é o erro de codificação URL mais comum que eu vejo, e é sutil. Você codifica uma string, depois passa para uma função que codifica novamente. Agora %20 (um espaço já codificado) vira %2520 porque o próprio % é codificado.
Exemplo do problema:
A solução: codificar valores uma única vez, no nível correto. Não codifique coisas que já estão codificadas.
Sinal de mais vs. %20 — Sim, é confuso
Em query strings de URL, espaços podem ser + ou %20. A convenção do + vem da codificação de formulários HTML (application/x-www-form-urlencoded). Em caminhos de URL, apenas %20 é válido.
Então https://example.com/hello world → o caminho é codificado como https://example.com/hello%20world
Mas https://example.com/search?q=hello world → a query pode ser ?q=hello+world ou ?q=hello%20world
encodeURI vs. encodeURIComponent
O JavaScript oferece duas funções, e usar a errada é um erro clássico:
encodeURI()— Codifica uma URL completa. Mantém:,/,?,#,&,=intactos pois são partes estruturais da URL.encodeURIComponent()— Codifica um componente de URL (como o valor de um parâmetro de consulta). Codifica SIM:,/,?,#,&,=pois podem fazer parte dos dados.
Regra prática: use encodeURIComponent() para valores, nunca para URLs inteiras. A documentação do MDN explica a diferença lindamente.
Outras linguagens
- Python:
urllib.parse.quote()para caminhos,urllib.parse.urlencode()para query strings — documentação aqui - Java:
URLEncoder.encode()(usa+para espaços — cuidado!) - PHP:
urlencode()para query strings,rawurlencode()para caminhos
Dicas rápidas
- Sempre codifique os valores dos parâmetros, nunca URLs inteiras
- Decodifique uma vez no lado receptor — não passe valores codificados por múltiplas camadas
- Teste com casos extremos: espaços,
&,=,#, caracteres não-ASCII e emoji
Construindo URLs com segurança em JavaScript
A forma correta de construir URLs com parâmetros de consulta é usando as APIs nativas URL e URLSearchParams. Elas cuidam de toda a codificação para você:
Perceba como URLSearchParams usa + para espaços (convenção de codificação de formulários HTML) e codifica corretamente o & no valor para que não seja confundido com o & que separa parâmetros. Isso é muito mais seguro do que concatenação de strings.
Armadilhas comuns da codificação URL
1. Codificar a URL inteira em vez de apenas os valores. Se você aplicar encodeURIComponent() em uma URL completa, vai codificar ://, /, ? e & — tornando a URL completamente inutilizável. Codifique apenas os valores individuais dos parâmetros.
2. Esquecer de codificar fragmentos hash. O caractere # em uma URL inicia um identificador de fragmento. Se seus dados contêm um # e você não codifica, tudo depois dele desaparece da perspectiva do servidor. O servidor nunca vê identificadores de fragmento — eles são apenas do lado do cliente.
3. Não lidar com nomes de domínio internacionais (IDN). Nomes de domínio com caracteres não-ASCII como example.日本 precisam de um tratamento especial chamado codificação Punycode. Isso é separado da codificação por porcentagem e se aplica apenas à parte do hostname da URL.
4. Codificar espaços de forma inconsistente. Algumas partes do seu sistema podem codificar espaços como + e outras como %20. Isso geralmente funciona bem para decodificação, mas pode causar problemas com comparação de URLs e cache. Escolha uma convenção e mantenha-a.
Referência rápida de codificação por porcentagem
| Caractere | Codificado | Por que precisa de codificação |
| Espaço | %20 ou + | Não permitido em URLs |
& | %26 | Separa parâmetros de consulta |
= | %3D | Separa chave de valor |
? | %3F | Inicia a query string |
# | %23 | Inicia o identificador de fragmento |
% | %25 | O próprio caractere de escape |
/ | %2F | Separador de caminho |
@ | %40 | Usado na seção de informações do usuário |
Codificação URL em diferentes contextos
A codificação URL não é só para URLs de navegador. Você vai encontrá-la nestas situações comuns:
- Requisições de API: Parâmetros de consulta em chamadas de API REST precisam de codificação adequada, especialmente se contiverem entrada do usuário
- URLs de redirecionamento: Quando você passa uma URL de retorno como parâmetro (como
?redirect=https://...), a URL de redirecionamento inteira precisa ser codificada como um valor - Fluxos OAuth: URLs de callback OAuth e parâmetros de estado são notoriamente complicados porque envolvem múltiplas camadas de codificação URL
- Deep links: Deep links móveis seguem as mesmas regras de codificação URL, mas algumas plataformas têm requisitos adicionais
Depurando problemas de codificação URL
Quando algo dá errado com a codificação URL, aqui está minha checklist de depuração:
1. Verifique codificação dupla — Procure por %25 na URL, o que significa que um % foi codificado duas vezes
2. Verifique a requisição bruta — Use a aba Network do DevTools do seu navegador para ver exatamente qual URL foi enviada, antes do navegador exibir a versão decodificada
3. Compare codificado vs. decodificado — Cole a URL problemática em um decodificador para ver o que ela realmente contém
4. Verifique a decodificação no servidor — Alguns frameworks decodificam parâmetros de URL automaticamente, e fazer isso manualmente por cima causa problemas
A anatomia de uma URL
Ok, vamos dar um passo atrás. Antes de irmos mais fundo na codificação, você precisa realmente entender do que uma URL é feita. Eu sei, eu sei — você usa URLs a carreira inteira. Mas aposto que não conhece todas as partes pelos nomes oficiais. A maioria dos devs não conhece, e é aí que a confusão com codificação começa.
De acordo com a RFC 3986, uma URL tem esta estrutura:
Deixe-me guiá-lo por cada parte:
- Scheme (
https,ftp,mailto) — O protocolo. Não precisa de codificação aqui, é sempre letras ASCII. - Authority — Isso inclui o opcional
user:password@(que você basicamente nunca deveria usar em 2026), o host (nome de domínio ou IP) e um número de porta opcional. - Path (
/search/results) — A parte hierárquica. Barras/separam segmentos. Dentro de cada segmento, você precisa codificar caracteres especiais, mas NÃO codifica as barras em si. - Query (
?q=hello&lang=en) — Pares chave-valor após o?. O&separa pares,=separa chaves de valores. Você codifica as chaves e valores, mas não os&e=estruturais. - Fragment (
#section-2) — A parte após o#. Essa é interessante — nunca é enviada ao servidor. É puramente do lado do cliente. Mas você ainda precisa codificar caracteres especiais dentro dela.
Aqui está o que confunde as pessoas: diferentes partes da URL têm diferentes regras de codificação. Uma / é perfeitamente válida no caminho (é um separador!) mas precisa ser codificada como %2F se aparecer dentro do valor de um parâmetro de consulta. Um @ é ok na seção de autoridade mas deve ser codificado no caminho. É por isso que funções de codificação genéricas causam tantos bugs.
Pense assim: a URL é uma frase com regras gramaticais. Os caracteres especiais são pontuação. Você não codificaria uma vírgula que está realmente sendo usada como vírgula — você só codifica uma vírgula que é parte dos dados e poderia ser confundida com pontuação.
encodeURI vs. encodeURIComponent: O campo minado do JavaScript
Tá bom, esse assunto me deixa absolutamente maluco porque vejo devs errando TODA hora. O JavaScript dá duas funções de codificação, e elas soam quase idênticas, mas usar a errada vai arruinar seu dia.
Deixe-me explicar claramente:
encodeURI() é projetado para codificar uma URL completa. Ele codifica caracteres inseguros mas deixa os estruturais em paz — coisas como :, /, ?, #, &, =, @. Porque se você está codificando uma URL completa, obviamente não quer quebrar a estrutura da URL.
encodeURIComponent() é projetado para codificar um valor individual que vai dentro de uma URL. Ele codifica TUDO exceto letras, dígitos e - _ . ~. Isso inclui :, /, ?, #, &, = — porque quando estes aparecem em um valor, são dados, não estrutura.
Aqui está uma comparação que deixa tudo cristalino:
| Caractere | encodeURI() | encodeURIComponent() |
: | : (inalterado) | %3A |
/ | / (inalterado) | %2F |
? | ? (inalterado) | %3F |
# | # (inalterado) | %23 |
& | & (inalterado) | %26 |
= | = (inalterado) | %3D |
@ | @ (inalterado) | %40 |
| Espaço | %20 | %20 |
é | %C3%A9 | %C3%A9 |
Agora veja o que acontece quando você usa a função errada:
E o erro oposto é igualmente ruim:
A regra de ouro: encodeURIComponent para valores, encodeURI para URLs completas. Ou melhor ainda, use a API URL e deixe o navegador cuidar disso. Sério, as classes URL e URLSearchParams existem por um motivo. Veja a documentação MDN do encodeURIComponent e a documentação MDN do encodeURI para todos os detalhes.
Codificação URL em diferentes linguagens
JavaScript não é a única linguagem com funções de codificação URL confusas. Cada linguagem tem suas peculiaridades, e acredite, algumas são até mais confusas que o par do JavaScript.
Python — Na verdade bem razoável, quando você encontra o módulo certo:
Java — Aqui a coisa fica estranha. URLEncoder foi projetado para codificação de formulários HTML, não para codificação URL geral. Então espaços viram + em vez de %20:
C# — O .NET na verdade dá as ferramentas certas, mas existem umas cinco métodos diferentes que fazem coisas levemente diferentes:
PHP — Ah, PHP. Claro que você tem duas funções com nomes quase idênticos que fazem coisas levemente diferentes:
Go — Limpo e sensato, como Go costuma ser:
A conclusão? Cada linguagem lida com o + vs %20 de forma diferente, e cada linguagem tem pelo menos uma função que vai te surpreender. Sempre verifique a documentação da linguagem que está usando. Não assuma que funciona igual ao JavaScript.
Unicode em URLs: O velho oeste
Ok, aqui a coisa fica REALMENTE interessante. O que acontece quando você coloca caracteres não-ASCII em uma URL? Tipo, e se você quiser uma URL com japonês, árabe ou — sem brincadeira — emoji?
A resposta envolve dois sistemas completamente diferentes, e misturá-los é um erro clássico.
Para o caminho e a query: Você usa codificação por porcentagem. Pegue os bytes UTF-8 do caractere e codifique cada um. Então café vira caf%C3%A9. Seu navegador faz isso automaticamente e geralmente mostra a versão bonita na barra de endereço, mas por baixo dos panos está enviando a versão codificada.
Para nomes de domínio: Codificação por porcentagem NÃO é usada. Em vez disso, existe um sistema chamado Punycode. Ele converte nomes de domínio Unicode em strings compatíveis com ASCII que começam com xn--.
Veja só:
café.com→xn--caf-dma.commünchen.de→xn--mnchen-3ya.de例え.jp→xn--r8jz45g.jp
Por que dois sistemas diferentes? Porque o DNS (o sistema que transforma nomes de domínio em endereços IP) foi construído nos anos 1980 e só suporta ASCII. Então tiveram que inventar uma forma de encaixar Unicode em strings ASCII — e Punycode é essa invenção. As partes de caminho e query de uma URL, por outro lado, são tratadas por servidores web que conseguem lidar com bytes codificados por porcentagem.
Na verdade existe uma especificação inteira para Unicode em URLs chamada IRI (Internationalized Resource Identifiers) definida na RFC 3987. Um IRI é basicamente uma URL que permite caracteres Unicode diretamente. Navegadores convertem IRIs em URIs nos bastidores.
E sim, domínios com emoji existem. 💩.la é um domínio real (ou foi em algum momento). É codificado com Punycode para xn--ls8h.la. Não recomendo usar domínios com emoji para nada sério, mas é uma prova divertida de que o sistema funciona.
Um detalhe sobre Unicode em URLs: diferentes representações Unicode do "mesmo" caractere. Por exemplo, é pode ser representado como um único codepoint (U+00E9) ou como e + um acento combinante (U+0065 + U+0301). Estes produzem strings codificadas diferentes! O padrão WHATWG URL recomenda normalização NFC, mas nem todos os sistemas seguem isso consistentemente.
Codificação dupla: O bug que assombra seus sonhos
Mencionei codificação dupla antes, mas ela merece um mergulho profundo porque esse bug provavelmente desperdiçou mais horas coletivas de desenvolvedor do que qualquer outro problema relacionado a URLs. Já passei por isso — várias vezes.
Aqui está o cenário básico:
O que aconteceu? Quando você codifica hello%20world uma segunda vez, o caractere % é codificado para %25. Então %20 vira %2520. O servidor vê a string literal %20 em vez de um espaço.
Isso parece óbvio quando eu explico assim, mas em bases de código reais é incrivelmente sorrateiro. Aqui estão os cenários onde codificação dupla te pega:
Cadeias de proxy. Você envia uma requisição para o servidor A, que a encaminha para o servidor B. Se ambos os servidores codificam a URL, boom — codificação dupla. API gateways como Kong, AWS API Gateway ou proxies reversos nginx são culpados comuns.
Cadeias de redirecionamento. O usuário vai para a página A, é redirecionado para a página B com um parâmetro ?returnUrl=..., e a página B redireciona novamente com a URL de retorno como parâmetro. Cada redirecionamento pode recodificar a URL. Após três redirecionamentos, sua URL está triplamente codificada e completamente inutilizada.
"Helpers" de frameworks. Alguns frameworks web codificam parâmetros de URL automaticamente. Se você codifica manualmente antes de passar para o framework, você obtém codificação dupla. Já vi isso acontecer com Spring Boot, middleware Express.js e o URL reversing do Django.
Como detectar codificação dupla? Procure por %25 na URL. Isso é um sinal de porcentagem que foi codificado, o que geralmente significa que algo foi codificado duas vezes. Se você vir %2520, é um espaço duplamente codificado. Se vir %253D, é um = duplamente codificado.
Como corrigir:
A melhor defesa é estabelecer limites claros no seu código: codifique nas bordas (logo antes de enviar uma requisição HTTP, ou logo antes de construir uma URL para exibição), e passe strings brutas e não codificadas em todo o resto internamente.
Limites de tamanho de URL e o que fazer sobre eles
Aqui vai algo que vai te surpreender: a especificação HTTP em si NÃO define um tamanho máximo de URL. A RFC 3986 diz que URLs devem ter "tamanho ilimitado." Mas o mundo real discorda.
Diferentes componentes na cadeia têm seus próprios limites, e o menor vence:
| Componente | Tamanho máximo da URL |
| Internet Explorer (RIP) | 2.083 caracteres |
| Chrome, Firefox, Safari | ~65.000+ caracteres |
| Apache (padrão) | 8.190 caracteres |
| Nginx (padrão) | 8.192 caracteres |
| IIS (padrão) | 16.384 caracteres |
| AWS ALB | 8.192 caracteres |
| Cloudflare | 32.768 caracteres |
Aquele antigo limite de 2.083 caracteres do IE costumava reger tudo. Embora o IE esteja basicamente morto agora, alguns desenvolvedores e ferramentas ainda o tratam como lei. Mas na prática, a maioria dos stacks modernos consegue lidar com URLs muito mais longas.
Dito isso, só porque você PODE fazer uma URL de 65.000 caracteres não significa que DEVERIA. Aqui estão alguns motivos reais para manter URLs curtas:
- Logs do servidor. Muitos sistemas de logging truncam URLs longas, o que torna a depuração um pesadelo.
- Copiar e colar. Usuários copiam e compartilham URLs. URLs super-longas quebram em e-mails, mensagens de chat e documentos.
- SEO. Mecanismos de busca geralmente recomendam manter URLs com menos de 2.000 caracteres.
- Cache. Alguns limites de chave de cache de CDN e proxy são baseados em URL. URLs mais longas = mais cache misses.
Então o que fazer quando sua URL fica longa demais? Que bom que perguntou:
1. Use POST em vez de GET. Se está enviando muitos dados, coloque-os no corpo da requisição. O corpo da requisição não tem limite prático de tamanho. Essa é a solução mais comum para formulários de busca complexos com muitos filtros.
2. Use encurtadores de URL ou IDs de referência. Gere um token curto que mapeia para o conjunto completo de parâmetros armazenados no servidor. Então em vez de /search?filter1=abc&filter2=def&filter3=... você tem /search/saved/abc123.
3. Comprima seus parâmetros. Alguns apps codificam em base64 um blob JSON comprimido e colocam na URL. Não é bonito, mas funciona. Você verá isso em ferramentas como URLs de dashboards do Grafana.
Codificação de formulários: application/x-www-form-urlencoded
Vamos falar sobre o elefante na sala que torna a codificação URL ainda mais confusa: codificação de formulários HTML. Quando você envia um formulário HTML com method="POST", o navegador codifica os dados do formulário usando um formato chamado application/x-www-form-urlencoded. E esse formato é QUASE igual à codificação por porcentagem padrão, mas com uma diferença chave que enlouquece todo mundo.
Espaços viram + em vez de %20.
É isso. Essa é a diferença principal. Mas nossa, quanta confusão causa.
Por que essa diferença existe? Razões históricas, claro. A especificação de codificação de formulários HTML é anterior à especificação de codificação URL, e usava + para espaços porque... bom, alguém achou que ficava mais bonito nos anos 90. E agora estamos presos com isso para sempre.
Quando você envia um formulário HTML, o navegador envia um cabeçalho Content-Type: application/x-www-form-urlencoded, e o servidor sabe interpretar + como espaços. Mas se você está construindo URLs manualmente em JavaScript e usa + para espaços na parte do caminho, o servidor verá sinais de mais literais. Que divertido.
Aqui é onde isso importa na prática:
E depois tem multipart/form-data, que é uma fera completamente diferente. Quando seu formulário inclui uploads de arquivo (), o navegador muda para codificação multipart/form-data, que usa boundaries para separar campos em vez de &. Não usa codificação URL de forma alguma — cada parte tem seus próprios cabeçalhos e corpo. Se você já tentou fazer parse manual de uma requisição multipart, conhece a dor.
O conselho prático: use URLSearchParams para query strings e dados de formulário. Use FormData para uploads de arquivo. Não tente codificar essas coisas manualmente, a menos que você realmente, realmente precise.
Experimente você mesmo
Trabalhando com URLs que parecem estranhas? Cole-as no nosso Decodificador URL para ver os caracteres reais. Precisa codificar um valor antes de colocá-lo em uma URL? O Codificador URL resolve instantaneamente. E para decompor URLs complexas em seus componentes, use o Parser de URL para ver cada parte claramente.