Qual é a maneira correta de codificar em URL caracteres Unicode?

107

Eu conheço o esquema% uxxxx não padrão, mas essa não parece uma escolha sábia, pois o esquema foi rejeitado pelo W3C.

Alguns exemplos interessantes:

O personagem do coração. Se eu digitar no meu navegador:

http://www.google.com/search?q=♥

Em seguida, copie e cole, vejo este URL

http://www.google.com/search?q=%E2%99%A5

o que faz parecer que o Firefox (ou Safari) está fazendo isso.

urllib.quote_plus(x.encode("latin-1"))
'%E2%99%A5'

o que faz sentido, exceto para coisas que não podem ser codificadas em Latin-1, como o caractere de ponto triplo.

Se eu digitar o URL

http://www.google.com/search?q=…

no meu navegador, copie e cole, eu obtenho

http://www.google.com/search?q=%E2%80%A6

costas. Que parece ser o resultado de fazer

urllib.quote_plus(x.encode("utf-8"))

o que faz sentido, pois ... não pode ser codificado com Latin-1.

Mas não está claro para mim como o navegador sabe se deve decodificar com UTF-8 ou Latin-1.

Uma vez que isso parece ser ambíguo:

In [67]: u"…".encode('utf-8').decode('latin-1')
Out[67]: u'\xc3\xa2\xc2\x80\xc2\xa6'

funciona, então não sei como o navegador descobre se deve decodificar isso com UTF-8 ou Latin-1.

Qual é a coisa certa a fazer com os personagens especiais com os quais preciso lidar?

Josh Gibson
fonte
19
Ambos os seus exemplos são codificados como UTF-8. O primeiro certamente não é Latin-1, visto que tem três bytes de comprimento ...
Jakob Borg
2
% E2% 99% A5 é hex para os valores de bytes do "terno coração preto" em UTF-8 . Esse coração negro não faz parte do conjunto de caracteres Latin-1 .
Hawkeye Parker
Para ver exatamente como e o que um navegador está codificando (e muitas outras informações úteis), use as ferramentas de desenvolvedor integradas à maioria dos navegadores modernos ou obtenha um depurador HTTP gratuito como o Fiddler .
Hawkeye Parker

Respostas:

65

Eu sempre codificaria em UTF-8. Na página da Wikipedia sobre codificação percentual :

A sintaxe genérica de URI determina que novos esquemas de URI que fornecem a representação de dados de caracteres em um URI devem, de fato, representar caracteres do conjunto não reservado sem tradução e devem converter todos os outros caracteres em bytes de acordo com UTF-8, e então codifique por cento esses valores. Esse requisito foi introduzido em janeiro de 2005 com a publicação do RFC 3986 . Os esquemas de URI introduzidos antes desta data não são afetados.

Parece que, como havia outras maneiras aceitas de fazer a codificação de URL no passado, os navegadores tentam vários métodos de decodificar um URI, mas se for você quem está fazendo a codificação, deve usar UTF-8.

John Biesnecker
fonte
8
UTF-8 também deve ser usado porque é a única codificação permitida pelo padrão IRI mais recente (RFC 3987, tools.ietf.org/html/rfc3986 ) que está substituindo o padrão de URL mais antigo.
Remy Lebeau
3
No caso de outros são tão surpreso quanto eu estava, o texto de @ RemyLebeau comentário menciona RFC3987, mas o link é para a especificação mais velho 3896. A URL correta é obviamente tools.ietf.org/html/rfc3987
tripleee
Sim, desculpe por isso. URI é definido pelo RFC 3986, IRI é definido pelo RFC 3987.
Remy Lebeau
10

A regra geral parece ser que os navegadores codificam as respostas do formulário de acordo com o tipo de conteúdo da página a partir da qual o formulário foi veiculado. Isso é uma suposição de que se o servidor nos enviar "text / xml; charset = iso-8859-1", então eles esperam respostas no mesmo formato.

Se você está apenas inserindo um URL na barra de URL, o navegador não tem uma página base para trabalhar e, portanto, só precisa adivinhar. Portanto, neste caso, parece estar fazendo utf-8 o tempo todo (já que ambas as entradas produziram valores de forma de três octetos).

A triste verdade é que a AFAIK não existe um padrão para qual conjunto de caracteres os valores em uma string de consulta, ou mesmo quaisquer caracteres no URL, devem ser interpretados como. Pelo menos no caso de valores na cadeia de consulta, não há nenhuma razão para supor que eles necessariamente fazer correspondem aos caracteres.

É um problema conhecido que você tem que dizer a sua estrutura de servidor que conjunto de caracteres que você espera a string de consulta para ser codificado como --- por exemplo, no Tomcat, você tem que chamar request.setEncoding () (ou algum método similar) antes de você chame qualquer um dos métodos request.getParameter (). A escassez de documentação sobre este assunto provavelmente reflete a falta de consciência do problema entre muitos desenvolvedores. (Eu regularmente pergunto aos entrevistados Java qual é a diferença entre um Reader e um InputStream, e regularmente recebo olhares em branco)

araqnid
fonte
6
RFC 3987 ( tools.ietf.org/html/rfc3986 ) define uma codificação padrão - UTF-8 deve ser usado ao codificar caracteres que não são permitidos não codificados.
Remy Lebeau
8

IRI ( RFC 3987 ) é o padrão mais recente que substitui os padrões URI / URL ( RFC 3986 e anteriores). URI / URL não oferece suporte nativo a Unicode (bem, RFC 3986 adiciona disposições para futuros protocolos baseados em URI / URL para suportá-lo, mas não atualiza RFCs anteriores). O esquema "% uXXXX" é uma extensão não padrão para permitir Unicode em algumas situações, mas não é implementado universalmente por todos. O IRI, por outro lado, oferece suporte total a Unicode e requer que o texto seja codificado como UTF-8 antes de ser codificado por cento.

Remy Lebeau
fonte
Desejo ver uma atualização dos protocolos para que o Unicode seja totalmente compatível com URLs, não apenas por codificação de porcentagem.
Mathieu J.
1
IRIs permite caracteres Unicode não codificados, exceto nos poucos casos em que os caracteres reservados devem ser codificados.
Remy Lebeau
6

IRIs não substituem URIs, porque apenas URIs (efetivamente, ASCII) são permitidos em alguns contextos - incluindo HTTP.

Em vez disso, você especifica um IRI e ele é transformado em um URI ao sair na rede.

Mark Nottingham
fonte
0

A primeira pergunta é quais são as suas necessidades? A codificação UTF-8 é um meio-termo muito bom entre obter texto criado com um editor barato e o suporte para uma ampla variedade de idiomas. Com relação ao navegador que identifica a codificação, a resposta (do servidor da web) deve informar ao navegador a codificação. Mesmo assim, a maioria dos navegadores tentará adivinhar, porque isso está faltando ou está errado em muitos casos. Eles adivinham lendo uma parte do fluxo de resultados para ver se há um caractere que não se encaixa na codificação padrão. Atualmente, todos os navegadores (? Eu não verifiquei isso, mas é quase verdade) usam utf-8 como padrão.

Portanto, use utf-8, a menos que tenha um motivo convincente para usar um dos muitos outros esquemas de codificação.

Pato
fonte