Encodage de caractères JSON - UTF-8 est-il bien pris en charge par les navigateurs ou dois-je utiliser des séquences d'échappement numériques?

89

J'écris un webservice qui utilise json pour représenter ses ressources, et je suis un peu coincé en réfléchissant à la meilleure façon d'encoder le json. En lisant le json rfc ( http://www.ietf.org/rfc/rfc4627.txt ), il est clair que l'encodage préféré est utf-8. Mais le rfc décrit également un mécanisme d'échappement de chaîne pour spécifier des caractères. Je suppose que cela serait généralement utilisé pour échapper aux caractères non-ascii, rendant ainsi le résultat utf-8 ascii valide.

Disons que j'ai une chaîne json qui contient des caractères unicode (points de code) qui ne sont pas ascii. Mon service Web devrait-il simplement encoder cela en utf-8 et le renvoyer, ou devrait-il échapper à tous ces caractères non-ascii et renvoyer de l'ascii pur?

J'aimerais que les navigateurs puissent exécuter les résultats en utilisant jsonp ou eval. Cela affecte-t-il la décision? Ma connaissance du support javascript de divers navigateurs pour utf-8 fait défaut.

EDIT: Je voulais préciser que ma principale préoccupation concernant la façon d'encoder les résultats concerne vraiment la gestion des résultats par le navigateur. Ce que j'ai lu indique que les navigateurs peuvent être sensibles au codage lors de l'utilisation de JSONP en particulier. Je n'ai pas trouvé de très bonnes informations sur le sujet, je vais donc devoir commencer à faire des tests pour voir ce qui se passe. Idéalement, je voudrais n'échapper que les quelques caractères requis et simplement utf-8 encoder les résultats.

schickb
la source

Réponses:

88

La spécification JSON nécessite la prise en charge de UTF-8 par les décodeurs. En conséquence, tous les décodeurs JSON peuvent gérer UTF-8 aussi bien qu'ils peuvent gérer les séquences d'échappement numériques. C'est également le cas pour les interpréteurs Javascript, ce qui signifie que JSONP gérera également le JSON encodé en UTF-8.

La possibilité pour les encodeurs JSON d'utiliser les séquences d'échappement numériques à la place vous offre simplement plus de choix. Une des raisons pour lesquelles vous pouvez choisir les séquences d'échappement numériques serait si un mécanisme de transport entre votre encodeur et le décodeur prévu n'est pas de sécurité binaire.

Une autre raison pour laquelle vous voudrez peut-être utiliser des séquences d'échappement numériques est d'empêcher certains caractères d'apparaître dans le flux, tels que <, &et ", qui peuvent être interprétés comme des séquences HTML si le code JSON est placé sans échapper dans HTML ou si un navigateur l'interprète à tort comme HTML . Cela peut être une défense contre l'injection HTML ou les scripts intersites (note: certains caractères DOIVENT être échappés dans JSON, y compris "et \).

Certains frameworks, y compris l'implémentation PHP de JSON, effectuent toujours les séquences d'échappement numériques du côté de l'encodeur pour tout caractère en dehors de ASCII. Ceci est destiné à une compatibilité maximale avec des mécanismes de transport limités et similaires. Cependant, cela ne doit pas être interprété comme une indication que les décodeurs JSON ont un problème avec UTF-8.

Donc, je suppose que vous pouvez simplement décider lequel utiliser comme ceci:

  • Utilisez simplement UTF-8, à moins que votre méthode de stockage ou de transport entre l'encodeur et le décodeur ne soit pas compatible avec les binaires.

  • Sinon, utilisez les séquences d'échappement numériques.

thomasrutter
la source
1
"Tous les décodeurs JSON peuvent gérer UTF-8" Bien que cela soit vrai pour les navigateurs, ce n'est pas parce que la norme l'exige que tous les logiciels de décodage JSON prennent en charge UTF-8.
Michael Mior
7
«Tous les décodeurs JSON peuvent gérer UTF-8» est littéralement vrai. Si quelque chose ne peut pas accepter UTF-8, ce n'est pas un décodeur JSON. C'est peut-être similaire à un décodeur JSON, mais ce n'en est certainement pas un.
thomasrutter
Je suppose que cela dépend de la définition du décodeur JSON que vous utilisez, mais bon point :)
Michael Mior
La raison pour laquelle la RFC 8259 spécifie la prise en charge de l'UTF-8 comme obligatoire est que c'est ce sur quoi le monde s'est normalisé. Les spécifications obsolètes précédentes définissaient les chaînes comme Unicode mais ne précisaient pas quel encodage; implémentations normalisées sur UTF-8 de toute façon et la spécification mise à jour reflète cela.
thomasrutter
Le support UTF-8 n'est pas spécifié comme obligatoire dans cette RFC pour un logiciel particulier pour autant que je sache. La seule mention de l'UTF-8 est qu'il doit être utilisé comme encodage pour JSON échangé en dehors d'un système fermé. Cela n'implique pas que tous les décodeurs JSON (un langage non utilisé dans la RFC) doivent prendre en charge UTF-8.
Michael Mior
17

J'ai eu un problème là-bas. Quand je JSON encode une chaîne avec un caractère comme "é", tous les navigateurs renverront le même "é", sauf IE qui retournera "\ u00e9".

Puis avec PHP json_decode (), il échouera s'il trouve "é", donc pour Firefox, Opera, Safari et Chrome, je dois appeler utf8_encode () avant json_decode ().

Remarque: avec mes tests, IE et Firefox utilisent leur objet JSON natif, d'autres navigateurs utilisent json2.js.

Tim Tisdall
la source
10
Vous vouliez probablement dire utf8_encode(), php.net/manual/en/function.utf8-encode.php
Binyamin
4
Si IE ne parvient pas à décoder cela, c'est un bogue dans le décodeur JSON que vous utilisez. Tous les décodeurs JSON doivent décoder avec succès la forme encodée, ou ils ne sont pas un décodeur JSON. Quant à votre problème avec json_decode () avec le é non échappé, il est possible que le texte que vous alimentez ne soit pas UTF-8. Les décodeurs JSON supposent toujours UTF-8, même l'implémentation PHP, même si PHP ne suppose normalement pas UTF-8 dans de nombreuses autres fonctions. Il existe d'autres encodages de caractères qui peuvent inclure un é non échappé et qui semblent identiques à l'écran, mais qui ne sont pas UTF-8. L'encodage sous la forme \ uXXXX est une solution de contournement à cela.
thomasrutter
Dire simplement: JSON peut légalement entrer dans n'importe quel encodage Unicode (UTF-8, UTF-16 BE / LE, UTF32 BE / LE, avec ou sans marqueur d'ordre d'octet). Et comme ASCII est un sous-ensemble de UTF-8, il peut également venir en ASCII. Si les analyseurs acceptent UTF-32 par exemple, je ne sais pas.
gnasher729
1
C'est correct et les analyseurs ne sont pas tenus de prendre en charge autre chose que UTF-8. D'après la spécification: "Le texte JSON DOIT être codé en UTF-8, UTF-16 ou UTF-32. Le codage par défaut est UTF-8, et les textes JSON codés en UTF-8 sont interopérables dans le sens où ils le seront être lu avec succès par le nombre maximum d'implémentations; il existe de nombreuses implémentations qui ne peuvent pas lire avec succès des textes dans d'autres encodages (tels que UTF-16 et UTF-32). Les implémentations NE DOIVENT PAS ajouter de marque d'ordre d'octet au début d'un texte JSON. "
thomasrutter
@thomasrutter La spécification que vous avez citée est ancienne. La spécification actuelle indique: "Le texte JSON échangé entre des systèmes qui ne font pas partie d'un écosystème fermé DOIT être codé en UTF-8. Les spécifications précédentes de JSON n'ont pas nécessité l'utilisation de UTF-8 lors de la transmission de texte JSON. Cependant, la grande majorité des implémentations logicielles basées sur JSON ont choisi d'utiliser le codage UTF-8, dans la mesure où c'est le seul encodage qui réalise l'interopérabilité. Les implémentations NE DOIVENT PAS ajouter de marque d'ordre d'octet (U + FEFF) au début d'une transmission en réseau Texte JSON. "
Remy Lebeau
12

L'ASCII n'en fait plus partie. L'utilisation du codage UTF-8 signifie que vous n'utilisez pas le codage ASCII. Ce que vous devez utiliser le mécanisme d'échappement est ce que dit la RFC:

Tous les caractères Unicode peuvent être placés entre guillemets à l'exception des caractères qui doivent être échappés: guillemets, solidus inversé et caractères de contrôle (U + 0000 à U + 001F)

le chaos
la source
1
Si vous lisez cette citation que vous avez fournie, vous verrez que vous n'êtes pas obligé d'échapper à tous les caractères Unicode, seulement quelques caractères spéciaux. Mais vous devez encoder les résultats (de préférence avec utf-8). La question est donc: "Pourquoi s'embêter à échapper des caractères Unicode normaux si vous êtes en encodage utf-8".
schickb
De plus, une chaîne encodée en ascii est un sous-ensemble pur de utf-8. Si j'utilise l'échappement de json pour tous les caractères non-ascii, le résultat est ascii - et donc utf-8. Diverses bibliothèques json (comme python simplejson) ont des modes pour forcer les résultats ascii. Je présume pour une raison, comme peut-être l'exécution dans les navigateurs.
schickb
Lorsque vous vous embêtez à échapper des caractères Unicode normaux, c'est dans des contextes où ce sont des métacaractères, comme des chaînes. (Le bloc RFC que j'ai cité concerne les chaînes; désolé, ce n'était pas clair à ce sujet.) Vous n'avez pas besoin de faire une sortie ASCII tout le temps; Je pense que c'est plus pour le débogage avec des navigateurs cassés.
chaos
7

J'étais confronté au même problème. Ça marche pour moi. S'il te plaît, vérifie cela.

json_encode($array,JSON_UNESCAPED_UNICODE);
Ankit Sewadik
la source
Il convient de noter que ce qui précède est PHP, car la question n'est en aucun cas spécifique à PHP et ne parle que du service Web qui peut également ne pas utiliser PHP (comme les plus anciens de nos lecteurs s'en souviennent peut-être encore…)
ntninja
1

En lisant le json rfc ( http://www.ietf.org/rfc/rfc4627.txt ), il est clair que l'encodage préféré est utf-8.

Pour info, la RFC 4627 n'est plus la spécification JSON officielle. Il a été obsolète en 2014 par RFC 7159 , qui a ensuite été obsolète en 2017 par RFC 8259 , qui est la spécification actuelle.

La RFC 8259 déclare:

8.1. Encodage de caractère

Le texte JSON échangé entre des systèmes qui ne font pas partie d'un écosystème fermé DOIT être codé en UTF-8 [RFC3629] .

Les spécifications précédentes de JSON ne nécessitaient pas l'utilisation de UTF-8 lors de la transmission de texte JSON. Cependant, la grande majorité des implémentations logicielles basées sur JSON ont choisi d'utiliser le codage UTF-8, dans la mesure où c'est le seul codage qui réalise l'interopérabilité.

Les implémentations NE DOIVENT PAS ajouter de marque d'ordre d'octet (U + FEFF) au début d'un texte JSON transmis en réseau. Dans l'intérêt de l'interopérabilité, les implémentations qui analysent les textes JSON PEUVENT ignorer la présence d'une marque d'ordre d'octet plutôt que de la traiter comme une erreur.

Remy Lebeau
la source
0

J'ai eu un problème similaire avec é char ... Je pense que le commentaire "il est possible que le texte que vous alimentez ne soit pas UTF-8" est probablement proche de la marque ici. J'ai le sentiment que le classement par défaut dans mon instance était autre chose jusqu'à ce que je réalise et change en utf8 ... le problème est que les données étaient déjà là, donc je ne sais pas si elles ont converti les données ou non lorsque je les ai modifiées, s'affiche bien dans mysql Table de travail. Le résultat final est que php ne codera pas json les données, mais renvoie simplement false. Peu importe le navigateur que vous utilisez comme serveur à l'origine de mon problème, php n'analysera pas les données vers utf8 si ce caractère est présent. Comme je le dis, je ne sais pas si cela est dû à la conversion du schéma en utf8 après la présence de données ou juste un bogue php. Dans ce cas, utilisezjson_encode(utf8_encode($string));

Paul Smith
la source