Em uma frase
A codificação de URL, oficialmente chamada de percent-encoding, é o processo de traduzir caracteres que têm significado especial ou são inválidos dentro de uma URL para um formato seguro e universalmente compreendido, para que possam ser transmitidos sem causar confusão.
O problema que resolve
Na sopa primordial da web primitiva, a vida era simples. As URLs — ou, de forma mais ampla, URIs (Uniform Resource Identifiers) — foram projetadas para serem uma maneira limpa e previsível de localizar um recurso. Os arquitetos, incluindo Sir Tim Berners-Lee, construíram esse sistema sobre uma base de um conjunto limitado de caracteres: o ASCII.
Isso funcionava muito bem, contanto que você só precisasse apontar para http://example.com/reports/April.html. Mas o que acontece quando as coisas ficam mais complicadas?
Considere a anatomia de uma URL. Ela tem partes: um esquema (http:), um host (example.com), um caminho (/search) e talvez uma query string (?q=dogs&cats). Certos caracteres são os maestros estruturais dessa orquestra. Os dois-pontos (:) separam o esquema. A barra (/) separa os segmentos do caminho. O ponto de interrogação (?) dá o pontapé inicial nos parâmetros da query. O "e" comercial (&) separa um parâmetro do outro.
É aqui que o problema começa. E se você quiser pesquisar pela string literal "C++ & C#"? Se você simplesmente tacar isso numa URL, você obtém .../search?q=C++ & C#. Um servidor web vê isso e fica totalmente confuso. Ele pensa que a busca é por "C++ ", e então vê um "&" e espera outro par de chave-valor, mas só encontra um solitário " C#". O caos. O significado pretendido se perdeu.
Além disso, alguns caracteres simplesmente não são permitidos. Um espaço é um encrenqueiro clássico. Quando um espaço faz parte de um nome de arquivo e quando é apenas um erro de digitação que um navegador deve ignorar? E quanto aos caracteres fora do alfabeto inglês básico? A web é global! Como você coloca Résumé.pdf ou 你好.html em uma URL projetada para ASCII?
O percent-encoding resolve toda essa classe de problemas. Ele fornece uma válvula de escape, uma maneira de dizer: "Ei, Sr. Servidor Web, o(s) próximo(s) caractere(s) não são estruturais. Não os interprete. Eles são dados literais." É o tradutor universal que garante que uma URL signifique a mesma coisa em um navegador no Brasil e em um servidor em Berlim.
Como funciona por debaixo dos panos
A "mágica" por trás do percent-encoding é surpreendentemente direta. É menos um passe de mágica e mais uma simples cifra de substituição que todos concordaram em usar.
O Elenco de Personagens: Reservados vs. Não Reservados
Primeiro, você precisa saber quais caracteres são "de boa" e quais são problemáticos. Eles se dividem em alguns grupos.
| Tipo de Caractere | Caracteres | Quando Codificar |
|---|---|---|
| Não Reservados | A-Z a-z 0-9 - _ . ~ |
Nunca. Estes são os VIPs do mundo das URLs. Eles são sempre seguros. |
| Reservados | : / ? # [ ] @ ! $ & ' ( ) * + , ; = |
Às vezes. Estes têm um significado estrutural especial. Se você quer usá-los por seu significado (como / num caminho), você não codifica. Se você quer usá-los como dados literais (como um & numa query de busca), você deve codificar. |
| Outros (Inseguros) | (espaço), `< > " % { } \ |
^` e todos os caracteres não-ASCII |
O ponto principal é o contexto. O caractere ? está ok se for o único ? que separa o caminho da query string. Mas se você precisa de um ponto de interrogação literal dentro do valor de um parâmetro da query, você deve codificá-lo.
O Truque de Mágica: Porcentagem + Hex
O processo de codificação é uma simples dança de três passos:
- Escolha um caractere que você precisa codificar. Vamos usar o "e" comercial
&. - Encontre seu valor em byte usando um conjunto de caracteres padrão. Para a web, esse padrão é UTF-8. Em UTF-8 (e seu predecessor ASCII), o caractere
&é representado pelo número decimal38. - Converta esse número para hexadecimal de dois dígitos e adicione um sinal de porcentagem (
%) antes. Decimal38é26em hexadecimal.
Então, & se torna %26.
Vamos tentar mais alguns:
- Um espaço é decimal
32, que é20em hexadecimal. Codificado:%20. - Um ponto de interrogação (
?) é decimal63, que é3Fem hexadecimal. Codificado:%3F. - O próprio sinal de porcentagem (
%) é decimal37,25em hexadecimal. Então, para codificar um%literal, você escreve%25.
Este sistema é brilhante porque o próprio sinal de porcentagem não é um caractere não reservado, então um parser sabe que sempre que vê um %, deve esperar que dois dígitos hexadecimais o sigam.
E quanto aos caracteres não-ingleses?
É aqui que o UTF-8 se torna crucial. Um caractere ASCII simples como A ocupa um byte. Mas um caractere como o é do francês ou o 好 do chinês é representado por múltiplos bytes em UTF-8. O processo de codificação é o mesmo, apenas repetido para cada byte.
Vamos pegar o é:
- Em UTF-8,
éé representado por dois bytes:C3eA9(em hexadecimal). - Codifique cada byte separadamente:
C3se torna%C3.A9se torna%A9.
- Combine-os:
ése torna%C3%A9.
O processo de decodificação é o inverso exato. Um navegador ou servidor vê %C3%A9, pega os dois bytes C3 e A9, passa-os por um decodificador UTF-8 e obtém de volta o belo caractere é.
Histórias da vida real
Teoria é ótima, mas vamos ver onde a teoria encontra a prática.
O Caso da Query de Busca que Desaparecia
Uma desenvolvedora júnior, Maya, estava construindo uma funcionalidade de busca para um site de documentação técnica. Os usuários podiam pesquisar por coisas como "C++", "promises & async/await", e assim por diante. Ela construiu a URL de busca simplesmente concatenando strings: site.com/search?q= + userInput.
As coisas deram tudo errado. Uma busca por promises & async/await gerou a URL .../search?q=promises & async/await. O servidor, no entanto, só registrou o termo de busca como "promises ". O & foi interpretado como um separador para um novo parâmetro, async/await, que foi descartado por não ter uma chave. Os resultados da busca dela estavam completamente errados.
A Lição: Maya aprendeu uma regra de ouro do desenvolvimento web: sempre aplique percent-encoding em qualquer dado dinâmico que for colocado em um componente de URL. Depois que ela começou a codificar a entrada do usuário, a URL tornou-se corretamente .../search?q=promises%20%26%20async%2Fawait. O servidor agora recebia a string completa e correta, e a busca funcionou perfeitamente.
O Incidente Internacional
Uma loja online decidiu destacar um novo produto de um parceiro alemão: o "Fußball." A equipe de marketing criou uma URL amigável para ele: store.com/products/Fußball. Em seus navegadores modernos no escritório, tudo parecia bem.
Mas o dia do lançamento foi um caos. Os tickets de suporte ao cliente choveram. Alguns usuários estavam recebendo erros "404 Not Found". Outros viam uma URL que parecia .../products/Fu%C3%9Fball na barra de endereço do navegador, enquanto alguns viam .../products/FuÃball. O sistema era uma colcha de retalhos de componentes antigos e novos, e eles não estavam lidando com o caractere não-ASCII ß (Eszett) de forma consistente. Algumas partes não o codificavam, algumas o codificavam assumindo UTF-8, e alguns sistemas legados o decodificavam assumindo um conjunto de caracteres diferente, resultando em mojibake.
A Lição: Confiar que navegadores e servidores vão "simplesmente lidar" com caracteres não-ASCII em URLs é uma receita para inconsistência. Codificar proativamente e consistentemente com percent-encoding todos os caracteres não-reservados usando o padrão UTF-8 garante que suas URLs sejam robustas e funcionem de forma previsível em todo o ecossistema da web, antigo e novo.
O Fiasco da Codificação Dupla
Uma equipe estava construindo um sistema de single sign-on (SSO). O fluxo funcionava assim: service-a.com redirecionaria o usuário para sso.com/login, passando sua própria URL como um parâmetro para que o usuário pudesse ser enviado de volta após o login. A URL de redirecionamento parecia assim: sso.com/login?redirect_uri=https://service-a.com/dashboard?param=1.
O desenvolvedor em service-a.com foi esperto e codificou o valor de redirect_uri, produzindo: sso.com/login?redirect_uri=https%3A%2F%2Fservice-a.com%2Fdashboard%3Fparam%3D1.
No entanto, o framework web que eles usavam tinha uma camada de middleware que, "por segurança," automaticamente codificava todas as query strings de saída. Ele viu a string já codificada e a codificou novamente. O % em %3A foi transformado em %25, então %3A se tornou %253A. A URL final era uma bagunça ilegível de codificação dupla. Quando o usuário chegava em sso.com, ele decodificava a URL uma vez e obtinha a string com codificação simples, que não podia usar como redirecionamento, quebrando completamente o fluxo de login.
A Lição: Esteja ciente de toda a sua cadeia de ferramentas. Codifique os dados no ponto de criação e garanta que nenhum outro sistema na linha de produção os codifique novamente. A codificação dupla é um bug comum e de quebrar a cabeça que transforma uma URL válida em lixo inútil.
Erros e armadilhas comuns
- Codificar a URL inteira. Nunca faça isso. Se você aplicar percent-encoding em
https://example.com, obterá algo comohttps%3A%2F%2Fexample.com. Isso não é mais uma URL válida; as partes do esquema e da autoridade agora são apenas uma confusão sem sentido de caracteres. Você deve codificar apenas os componentes individuais que precisam (como valores de parâmetros de query ou segmentos de caminho específicos). - Não codificar de jeito nenhum. O pecado mais frequente. Empurrar dados brutos do usuário ou dados com caracteres especiais diretamente em uma string de URL é pedir para ter falhas de segurança (como Cross-Site Scripting) e funcionalidades quebradas.
- Esquecer do contexto. O caractere
&é aceitável no caminho de uma URL, mas é um separador reservado na query string. O mesmo vale para/. Você não precisa codificar caracteres reservados quando eles estão sendo usados para seu propósito especial. - Confundir
+com%20. No tipo de conteúdoapplication/x-www-form-urlencoded(usado por formulários HTML), os espaços são frequentemente codificados como um sinal de+na query string. Embora muitos servidores entendam isso, o percent-encoding oficial para um espaço é%20. Usar%20não é ambíguo e funciona corretamente em todas as partes de uma URL, não apenas na query string. Na dúvida, fique com%20. - Usar um conjunto de caracteres desatualizado. A web funciona com UTF-8. Se você codificar seus dados usando um conjunto de caracteres diferente (como ISO-8859-1), um servidor esperando UTF-8 interpretará mal os bytes e corromperá seus dados. Sempre especifique e use UTF-8.
Por que isso deve estar no seu radar
Se você escreve código que mexe com uma URL, você precisa entender o percent-encoding. Não é opcional. Você deve pensar sobre isso sempre que estiver:
- Construindo uma URL a partir de variáveis ou entrada do usuário.
- Fazendo uma requisição de API com parâmetros na URL.
- Lidando com caracteres internacionais em nomes de arquivos, perfis de usuário ou conteúdo que possa aparecer em uma URL.
- Analisando uma URL no lado do servidor para extrair dados.
- Escrevendo redirecionamentos ou passando URLs como parâmetros para outros serviços.
Em resumo, o percent-encoding é uma peça fundamental do encanamento da web. Ignorá-lo leva a software com bugs, inseguro e não confiável. Saber como funciona é um sinal de um desenvolvedor web profissional.
Vá mais fundo
- RFC 3986: A especificação canônica para Uniform Resource Identifier (URI). A Seção 2 define o conjunto de caracteres e as regras de percent-encoding. É a fonte definitiva da verdade.
- MDN Web Docs: encodeURIComponent(): Um guia prático para desenvolvedores JavaScript, explicando qual função usar e por quê. A seção "Veja também" contém links para outras funções de codificação relacionadas.
- Wikipedia: Percent-encoding: Uma visão geral abrangente e de fácil leitura do conceito, sua história e suas várias nuances.
- W3C: Character encodings: Uma introdução de alto nível sobre por que as codificações de caracteres são importantes na web, com o UTF-8 como o herói da história.