Que signifie «Content-type: application / json; charset = utf-8 "signifie vraiment?

284

Lorsque je fais une demande POST avec un corps JSON à mon service REST, j'inclus Content-type: application/json; charset=utf-8dans l'en-tête du message. Sans cet en-tête, je reçois une erreur du service. Je peux également utiliser avec succès Content-type: application/jsonsans la ;charset=utf-8portion.

Que fait exactement charset=utf-8? Je sais que cela spécifie l'encodage des caractères mais le service fonctionne bien sans lui. Cet encodage limite-t-il les caractères pouvant figurer dans le corps du message?

DenaliHardtail
la source
4
jetez un oeil à hanselman.com/blog/…
Daniel Powell
8
Curieusement, selon l' application/jsonenregistrement de type de média de l'IANA , il ne semble pas y avoir de charsetparamètre pris en charge du tout, bien qu'il soit souvent fourni dans la pratique.
Uux
1
I know it specifies the character encoding but the service works fine without it.«travailler» ne signifie pas toujours «le code / la configuration existante est la manière la plus correcte de couvrir tous les cas de coin pour faire une chose». Cela dépend de toutes les conventions et hypothèses qui peuvent ne pas fonctionner dans d'autres circonstances. Pour moi personnellement, j'essaie toujours d'être aussi explicite que possible.
WesternGun
3
L'envoi d'un paramètre "charset" est incorrect et vide de sens. Voir RFC 8259, section 11, dernière phrase.
Julian Reschke

Réponses:

283

L'en-tête indique simplement dans quoi le contenu est codé. Il n'est pas nécessairement possible de déduire le type du contenu du contenu lui-même, c'est-à-dire que vous ne pouvez pas nécessairement simplement regarder le contenu et savoir quoi en faire. C'est à cela que servent les en-têtes HTTP, ils indiquent au destinataire à quel type de contenu ils sont (censément) confrontés.

Content-type: application/json; charset=utf-8désigne le contenu au format JSON, codé dans le codage de caractères UTF-8. La désignation du codage est quelque peu redondante pour JSON, car le codage par défaut (uniquement?) Pour JSON est UTF-8. Donc, dans ce cas, le serveur de réception est apparemment heureux de savoir qu'il traite JSON et suppose que l'encodage est UTF-8 par défaut, c'est pourquoi il fonctionne avec ou sans en-tête.

Cet encodage limite-t-il les caractères pouvant figurer dans le corps du message?

Non. Vous pouvez envoyer tout ce que vous voulez dans l'en-tête et le corps. Mais, si les deux ne correspondent pas, vous pouvez obtenir des résultats erronés. Si vous spécifiez dans l'en-tête que le contenu est encodé en UTF-8 mais que vous envoyez en fait du contenu encodé en Latin1, le récepteur peut produire des données inutiles, essayant d'interpréter les données encodées en Latin1 comme UTF-8. Si bien sûr vous spécifiez que vous envoyez des données encodées en Latin1 et que vous le faites réellement, alors oui, vous êtes limité aux 256 caractères que vous pouvez encoder en Latin1.

décomposer
la source
4
Bien sûr, dans JSON, vous pouvez toujours représenter des caractères non latins1 en utilisant des séquences d'échappement comme \u20AC.
dan04
31
Selon la norme pour json, vous n'êtes pas autorisé à utiliser latin1 pour l'encodage du contenu. Le contenu JSON doit être codé en unicode, que ce soit UTF-8, UTF-16 ou UTF-32 (gros ou petit endian).
Daniel Luna
20
Il n'y a pas de paramètre charset sur application / json.
Julian Reschke
7
@DanielLuna a raison, application/jsondoit être dans l'un des formats de transformation ucs. De plus, comme les quatre premiers octets de JSON sont limités, vous pouvez toujours dire s'il s'agit de 8, 16 ou 32 et de son endianité.
Jason Coco
4
Événement s'il est redondant, vous pouvez inclure charset=utf-8pour des raisons de sécurité: github.com/shieldfy/API-Security-Checklist/issues/25
manuc66
143

Pour justifier l'affirmation de @ deceze selon laquelle l'encodage JSON par défaut est UTF-8 ...

De l' IETF RFC4627 :

Le texte JSON DOIT être codé en Unicode. L'encodage par défaut est UTF-8.

Étant donné que les deux premiers caractères d'un texte JSON seront toujours des caractères ASCII [RFC0020], il est possible de déterminer si un flux d'octets est UTF-8, UTF-16 (BE ou LE) ou UTF-32 (BE ou LE) en regardant le modèle de null dans les quatre premiers octets.

      00 00 00 xx  UTF-32BE
      00 xx 00 xx  UTF-16BE
      xx 00 00 00  UTF-32LE
      xx 00 xx 00  UTF-16LE
      xx xx xx xx  UTF-8
Drew Noakes
la source
12
Il est toujours utile de considérer JSON comme un format binaire, pas un format texte.
Sulthan
2
Maintenant que la RFC4627 a été obsolète par la RFC7159, qui indique que la valeur racine peut être une chaîne (en contraste explicite avec l'ancienne spécification), comment est-ce maintenant implémenté? La spécification est vague à cet égard et dit simplement que trois encodages sont autorisés, mais pas comment on est censé les différencier.
Fabio Beltramini du
4
@FabioBeltramini Ce qui précède devrait toujours tenir, car une chaîne en JSON ne contiendra aucun caractère nul littéral (les null en JSON devraient être encodés avec une séquence d'échappement numérique, par exemple "\u0000").
thomasrutter du
3
En fait, le deuxième caractère dans UTF-16xx peut ne pas avoir de NULL dans ce cas, mais il sera toujours possible de déterminer le codage à partir des autres octets: xx 00 00 00est toujours UTF-32LE et xx 00 xx xxest toujours UTF-16LE, 00 xx xx xxest toujours UTF-16BE.
thomasrutter
20

Notez que l' IETF RFC4627 a été remplacé par l' IETF RFC7158 . Dans la section [8.1], il rétracte le texte cité par @Drew plus tôt en disant:

Implementations MUST NOT add a byte order mark to the beginning of a JSON text.
Alex
la source
L'hypothèse est toujours valable, car tout json valide commencera toujours par deux caractères ascii.
Larsing
Un caractère, car un seul chiffre est un fichier JSON valide
Nayuki
0

Je suis exactement d'accord avec @deceze, mais je souhaite développer cette partie de la question "Je reçois une erreur du service" ,

Nous obtenons ce genre d'erreurs comme http 415

Erreur de type de support Http 415 non pris en charge

Le code de réponse d'erreur du client de type de support HTTP 415 non pris en charge indique que le serveur refuse d'accepter la demande car le format de la charge utile est dans un format non pris en charge.

Le problème de format peut être dû au type de contenu ou au codage de contenu indiqué dans la demande , ou à l'inspection directe des données.

En d'autres termes, comme vu dans https://stackoverflow.com/a/22643964/914284 cet exemple.

  • Nous devons définir le type de contenu correct et nous devons accepter le bon type de contenu, comme indiqué. Ajouter Content-Type: application / json et Accept: application / json. Sinon, il assumera la valeur par défaut
Hamit YILDIRIM
la source
0

L'implémentation de Dart http traite les octets grâce à ce "charset = utf-8", donc je suis sûr que plusieurs implémentations le supportent, pour éviter le jeu de caractères de secours "latin-1" lors de la lecture des octets de la réponse. Dans mon cas, je perds totalement le format sur la chaîne du corps de la réponse, donc je dois faire l'encodage des octets manuellement dans utf8, ou ajouter ce paramètre "interne" d'en-tête sur la réponse API de mon serveur.

roipeker
la source
0

J'utilisais HttpClient et récupérais l'en-tête de réponse avec le type de contenu de application/json, j'ai perdu des caractères tels que des langues étrangères ou des symboles qui utilisaient unicode car HttpClient est par défaut ISO-8859-1 . Donc, soyez aussi explicite que possible comme mentionné par @WesternGun pour éviter tout problème possible.

Il n'y a aucun moyen de gérer le fait que le serveur ne gère pas charset ( method.setRequestHeader("accept-charset", "UTF-8");) d' en-tête demandé pour moi et j'ai dû récupérer les données de réponse sous forme d'octets de dessin et les convertir en chaîne en utilisant UTF-8. Il est donc recommandé d'être explicite et d'éviter l'hypothèse d'une valeur par défaut.

Tri Nguyen
la source