¿Cuál es la forma correcta de codificar en URL los caracteres Unicode?

107

Conozco el esquema% uxxxx no estándar, pero no parece una elección acertada ya que el esquema ha sido rechazado por el W3C.

Algunos ejemplos interesantes:

El personaje del corazón. Si escribo esto en mi navegador:

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

Luego cópielo y péguelo, veo esta URL

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

lo que hace que parezca que Firefox (o Safari) está haciendo esto.

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

lo cual tiene sentido, excepto para las cosas que no se pueden codificar en Latin-1, como el carácter de punto triple.

Si escribo la URL

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

en mi navegador, luego copie y pegue, obtengo

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

espalda. Que parece ser el resultado de hacer

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

lo cual tiene sentido ya que… no se puede codificar con Latin-1.

Pero no me queda claro cómo el navegador sabe si decodificar con UTF-8 o Latin-1.

Dado que esto parece ser ambiguo:

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

funciona, así que no sé cómo el navegador se da cuenta de si decodificar eso con UTF-8 o Latin-1.

¿Qué es lo correcto para hacer con los caracteres especiales con los que debo lidiar?

Josh Gibson
fuente
19
Ambos ejemplos están codificados como UTF-8. El primero ciertamente no es Latin-1, dado que tiene tres bytes de longitud ...
Jakob Borg
2
% E2% 99% A5 es hexadecimal para los valores de bytes del "traje de corazón negro" en UTF-8 . Ese corazón negro no es parte del conjunto de caracteres Latin-1 .
Hawkeye Parker
Para ver exactamente cómo y qué está codificando un navegador (y mucha otra información útil), use las herramientas de desarrollo integradas en la mayoría de los navegadores modernos u obtenga un depurador HTTP gratuito como Fiddler .
Hawkeye Parker

Respuestas:

65

Siempre codificaría en UTF-8. De la página de Wikipedia sobre codificación porcentual :

La sintaxis de URI genérica exige que los nuevos esquemas de URI que proporcionan la representación de datos de caracteres en un URI deben, en efecto, representar caracteres del conjunto no reservado sin traducción, y deben convertir todos los demás caracteres a bytes de acuerdo con UTF-8, y luego codificar en porcentaje esos valores. Este requisito se introdujo en enero de 2005 con la publicación de RFC 3986 . Los esquemas de URI introducidos antes de esta fecha no se ven afectados.

Parece que debido a que existían otras formas aceptadas de codificar URL en el pasado, los navegadores intentan varios métodos para decodificar un URI, pero si eres tú quien realiza la codificación, debes usar UTF-8.

John Biesnecker
fuente
8
También se debe utilizar UTF-8 porque es la única codificación permitida por el estándar IRI más nuevo (RFC 3987, tools.ietf.org/html/rfc3986 ) que reemplaza al estándar de URL anterior.
Remy Lebeau
3
En caso de que otros estén tan sorprendidos como yo, el texto en el comentario de @ RemyLebeau menciona RFC3987, pero el enlace es a la especificación anterior 3896. La URL correcta es obviamente tools.ietf.org/html/rfc3987
tripleee
Sí, lo siento por eso. URI está definido por RFC 3986, IRI está definido por RFC 3987.
Remy Lebeau
10

La regla general parece ser que los navegadores codifican las respuestas de los formularios de acuerdo con el tipo de contenido de la página desde la que se sirvió el formulario. Esta es una suposición de que si el servidor nos envía "text / xml; charset = iso-8859-1", entonces esperan respuestas en el mismo formato.

Si solo está ingresando una URL en la barra de URL, entonces el navegador no tiene una página base para trabajar y, por lo tanto, solo tiene que adivinar. Entonces, en este caso, parece estar haciendo utf-8 todo el tiempo (ya que ambas entradas produjeron valores de forma de tres octetos).

La triste verdad es que AFAIK no existe un estándar para el conjunto de caracteres que deben interpretarse los valores en una cadena de consulta o, de hecho, cualquier carácter en la URL. Al menos en el caso de los valores en la cadena de consulta, no hay razón para suponer que necesariamente se hacen corresponden a los caracteres.

Es un problema conocido que tiene que decirle al marco de su servidor con qué conjunto de caracteres espera que se codifique la cadena de consulta; por ejemplo, en Tomcat, debe llamar a request.setEncoding () (o algún método similar) antes que usted llamar a cualquiera de los métodos request.getParameter (). La escasez de documentación sobre este tema probablemente refleja la falta de conciencia del problema entre muchos desarrolladores. (Regularmente pregunto a los entrevistados de Java cuál es la diferencia entre un Reader y un InputStream, y con regularidad obtengo miradas en blanco)

arácnido
fuente
6
RFC 3987 ( tools.ietf.org/html/rfc3986 ) define una codificación estándar: se debe usar UTF-8 al codificar caracteres que de otro modo no se permitirían sin codificar.
Remy Lebeau
8

IRI ( RFC 3987 ) es el último estándar que reemplaza a los estándares URI / URL ( RFC 3986 y anteriores). URI / URL no admite de forma nativa Unicode (bueno, RFC 3986 agrega disposiciones para futuros protocolos basados ​​en URI / URL para admitirlo, pero no actualiza RFC anteriores). El esquema "% uXXXX" es una extensión no estándar para permitir Unicode en algunas situaciones, pero no todos lo implementan universalmente. IRI, por otro lado, es totalmente compatible con Unicode y requiere que el texto se codifique como UTF-8 antes de ser codificado en porcentaje.

Remy Lebeau
fuente
Deseo ver una actualización de los protocolos para que unicode sea totalmente compatible con las URL, no solo mediante la codificación porcentual.
Mathieu J.
1
Los IRI permiten caracteres Unicode no codificados, excepto en los pocos casos en los que los caracteres reservados deben codificarse.
Remy Lebeau
6

Los IRI no reemplazan a los URI, porque solo los URI (efectivamente, ASCII) están permitidos en algunos contextos, incluido HTTP.

En cambio, especifica un IRI y se transforma en un URI cuando sale por el cable.

Mark Nottingham
fuente
0

La primera pregunta es ¿cuáles son sus necesidades? La codificación UTF-8 es un compromiso bastante bueno entre tomar texto creado con un editor económico y soporte para una amplia variedad de idiomas. En lo que respecta a la identificación del navegador de la codificación, la respuesta (del servidor web) debe indicarle al navegador la codificación. Aún así, la mayoría de los navegadores intentarán adivinar, porque esto falta o es incorrecto en muchos casos. Adivinan leyendo una parte del flujo de resultados para ver si hay un carácter que no encaja en la codificación predeterminada. Actualmente, todos los navegadores (? No marqué esto, pero es bastante cierto) usan utf-8 como predeterminado.

Por lo tanto, use utf-8 a menos que tenga una razón convincente para usar uno de los muchos otros esquemas de codificación.

Pat O
fuente