Quelle est la bonne façon d'encoder les caractères Unicode par URL?

107

Je connais le schéma non standard% uxxxx mais cela ne semble pas être un choix judicieux puisque le schéma a été rejeté par le W3C.

Quelques exemples intéressants:

Le caractère du cœur. Si je tape ceci dans mon navigateur:

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

Puis copiez et collez-le, je vois cette URL

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

ce qui donne l'impression que Firefox (ou Safari) le fait.

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

ce qui a du sens, sauf pour les choses qui ne peuvent pas être encodées en Latin-1, comme le caractère triple point.

Si je tape l'URL

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

dans mon navigateur puis copiez et collez, j'obtiens

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

arrière. Ce qui semble être le résultat de

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

ce qui a du sens puisque… ne peut pas être encodé avec Latin-1.

Mais alors ce n'est pas clair pour moi comment le navigateur sait s'il doit décoder avec UTF-8 ou Latin-1.

Puisque cela semble ambigu:

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

fonctionne, donc je ne sais pas comment le navigateur détermine s'il faut décoder cela avec UTF-8 ou Latin-1.

Quelle est la bonne chose à faire avec les caractères spéciaux avec lesquels je dois traiter?

Josh Gibson
la source
19
Vos deux exemples sont encodés en UTF-8. Le premier n'est certainement pas Latin-1, étant donné qu'il fait trois octets de long ...
Jakob Borg
2
% E2% 99% A5 est hexadécimal pour les valeurs d'octet de la "combinaison de coeur noir" en UTF-8 . Ce cœur noir ne fait pas partie du jeu de caractères Latin-1 .
Hawkeye Parker
Pour voir de manière fiable exactement comment et ce qu'un navigateur encode (et beaucoup d'autres informations utiles), utilisez les outils de développement intégrés à la plupart des navigateurs modernes ou obtenez un débogueur HTTP gratuit comme Fiddler .
Hawkeye Parker

Réponses:

65

Je coderais toujours en UTF-8. À partir de la page Wikipedia sur l'encodage en pourcentage :

La syntaxe générique d'URI exige que les nouveaux schémas d'URI qui fournissent la représentation des données de caractère dans un URI doivent, en effet, représenter les caractères de l'ensemble non réservé sans traduction, et doivent convertir tous les autres caractères en octets selon UTF-8, puis encodez en pourcentage ces valeurs. Cette exigence a été introduite en janvier 2005 avec la publication de la RFC 3986 . Les schémas d'URI introduits avant cette date ne sont pas affectés.

Il semble que, comme il y avait d'autres méthodes acceptées d'encodage d'URL dans le passé, les navigateurs tentent plusieurs méthodes de décodage d'un URI, mais si c'est vous qui faites l'encodage, vous devriez utiliser UTF-8.

John Biesnecker
la source
8
UTF-8 doit également être utilisé car c'est le seul encodage autorisé par la nouvelle norme IRI (RFC 3987, tools.ietf.org/html/rfc3986 ) qui remplace l'ancienne norme URL.
Remy Lebeau
3
Au cas où d'autres seraient aussi surpris que moi, le texte du commentaire de @ RemyLebeau mentionne RFC3987, mais le lien est vers l'ancienne spécification 3896. L'URL correcte est évidemment tools.ietf.org/html/rfc3987
tripleee
Ouais, désolé pour ça. URI est défini par RFC 3986, IRI est défini par RFC 3987.
Remy Lebeau
10

La règle générale semble être que les navigateurs encodent les réponses au formulaire en fonction du type de contenu de la page à partir de laquelle le formulaire a été diffusé. C'est une supposition que si le serveur nous envoie "text / xml; charset = iso-8859-1", alors il attend des réponses dans le même format.

Si vous entrez simplement une URL dans la barre d'URL, le navigateur n'a pas de page de base sur laquelle travailler et n'a donc qu'à deviner. Donc, dans ce cas, il semble faire utf-8 tout le temps (puisque vos deux entrées ont produit des valeurs de forme de trois octets).

La triste vérité est qu'AFAIK il n'y a pas de norme pour quel jeu de caractères les valeurs d'une chaîne de requête, ou en fait les caractères de l'URL, doivent être interprétés comme. Au moins dans le cas des valeurs dans la chaîne de requête, il n'y a aucune raison de supposer qu'ils nécessairement faire correspondent aux caractères.

Il est un problème connu que vous devez dire à votre cadre de serveur qui le caractère que vous définissez vous attendez la chaîne de requête à coder comme --- par exemple, dans Tomcat, vous devez appeler request.setEncoding () (ou une méthode similaire) avant que vous appelez l'une des méthodes request.getParameter (). Le manque de documentation sur ce sujet reflète probablement le manque de conscience du problème chez de nombreux développeurs. (Je demande régulièrement aux interviewés Java quelle est la différence entre un Reader et un InputStream, et j'ai régulièrement des regards vides)

araqnid
la source
6
La RFC 3987 ( tools.ietf.org/html/rfc3986 ) définit un codage standard - UTF-8 doit être utilisé lors du codage de caractères qui ne sont pas autorisés autrement sans codage.
Remy Lebeau
8

IRI ( RFC 3987 ) est la dernière norme qui remplace les normes URI / URL ( RFC 3986 et plus anciennes). URI / URL ne prend pas en charge nativement Unicode (enfin, la RFC 3986 ajoute des dispositions pour les futurs protocoles basés sur URI / URL pour la prendre en charge, mais ne met pas à jour les RFC passées). Le schéma "% uXXXX" est une extension non standard pour autoriser Unicode dans certaines situations, mais n'est pas universellement implémenté par tout le monde. IRI, d'autre part, prend entièrement en charge Unicode et nécessite que le texte soit encodé en UTF-8 avant d'être ensuite encodé en pourcentage.

Remy Lebeau
la source
Je souhaite voir une mise à jour des protocoles afin que l'unicode soit entièrement pris en charge dans les URL, pas seulement via le codage en pourcentage.
Mathieu J.
1
Les adresses IRI autorisent les caractères Unicode non codés, sauf dans les rares cas où des caractères réservés doivent être codés.
Remy Lebeau
6

Les IRI ne remplacent pas les URI, car seuls les URI (en fait, ASCII) sont autorisés dans certains contextes, y compris HTTP.

Au lieu de cela, vous spécifiez un IRI et il est transformé en URI lors de la sortie sur le fil.

Mark Nottingham
la source
0

La première question est quels sont vos besoins? L'encodage UTF-8 est un assez bon compromis entre la prise de texte créé avec un éditeur bon marché et la prise en charge d'une grande variété de langues. En ce qui concerne le navigateur identifiant le codage, la réponse (du serveur Web) doit indiquer au navigateur le codage. Pourtant, la plupart des navigateurs tenteront de deviner, car cela est manquant ou erroné dans de nombreux cas. Ils devinent en lisant une partie du flux de résultats pour voir s'il y a un caractère qui ne rentre pas dans l'encodage par défaut. Actuellement, tous les navigateurs (? Je n'ai pas vérifié cela, mais c'est assez proche de vrai) utilisent utf-8 par défaut.

Utilisez donc utf-8 à moins que vous n'ayez une raison impérieuse d'utiliser l'un des nombreux autres schémas d'encodage.

Pat O
la source