Was bedeutet “Inhaltstyp: application / json; Zeichensatz = utf-8 ”wirklich bedeuten?

284

Wenn ich eine POST-Anfrage mit einem JSON-Body an meinen REST-Service stelle, füge ich sie Content-type: application/json; charset=utf-8in den Nachrichtenkopf ein. Ohne diesen Header erhalte ich eine Fehlermeldung vom Dienst. Ich kann auch erfolgreich Content-type: application/jsonohne die ;charset=utf-8Portion verwenden.

Was genau macht charset=utf-8das? Ich weiß, dass es die Zeichenkodierung angibt, aber der Dienst funktioniert ohne sie einwandfrei. Beschränkt diese Codierung die Zeichen, die sich im Nachrichtentext befinden können?

DenaliHardtail
quelle
4
Werfen Sie
Daniel Powell
8
Erstaunlicherweise nach der IANA application/jsonMedientyp Registrierung , wird es nicht angezeigt , ein unterstützt werden charsetParameter überhaupt, wenn auch in der Praxis häufig zugeführt wird.
Uux
1
I know it specifies the character encoding but the service works fine without it."Arbeiten" bedeutet nicht immer "Der vorhandene Code / die vorhandene Konfiguration ist der korrekteste Weg, um alle Eckfälle abzudecken und eine Sache zu tun". Dies hängt von allen Konventionen und Annahmen ab, die unter anderen Umständen möglicherweise nicht funktionieren. Für mich persönlich versuche ich immer, so explizit wie möglich zu sein.
WesternGun
3
Das Senden eines "Zeichensatz" -Parameters ist falsch und bedeutungslos. Siehe RFC 8259, Abschnitt 11, letzter Satz.
Julian Reschke

Antworten:

283

Der Header gibt nur an, in was der Inhalt codiert ist. Es ist nicht unbedingt möglich, den Typ des Inhalts aus dem Inhalt selbst abzuleiten, dh Sie können nicht unbedingt nur den Inhalt betrachten und wissen, was damit zu tun ist. Dafür sind HTTP-Header gedacht. Sie teilen dem Empfänger mit, um welche Art von Inhalten es sich (angeblich) handelt.

Content-type: application/json; charset=utf-8bezeichnet den Inhalt im JSON-Format, das in der UTF-8-Zeichencodierung codiert ist. Das Festlegen der Codierung ist für JSON etwas redundant, da die Standardcodierung (nur?) Für JSON UTF-8 ist. In diesem Fall ist der empfangende Server anscheinend froh zu wissen, dass es sich um JSON handelt, und geht davon aus, dass die Codierung standardmäßig UTF-8 ist. Deshalb funktioniert er mit oder ohne Header.

Beschränkt diese Codierung die Zeichen, die sich im Nachrichtentext befinden können?

Nein. Sie können im Header und im Body alles senden, was Sie wollen. Wenn die beiden jedoch nicht übereinstimmen, erhalten Sie möglicherweise falsche Ergebnisse. Wenn Sie im Header angeben, dass der Inhalt UTF-8-codiert ist, Sie jedoch tatsächlich Latin1-codierten Inhalt senden, erzeugt der Empfänger möglicherweise Mülldaten und versucht, Latin1-codierte Daten als UTF-8 zu interpretieren. Wenn Sie natürlich angeben, dass Sie Latin1-codierte Daten senden und dies tatsächlich tun, sind Sie auf die 256 Zeichen beschränkt, die Sie in Latin1 codieren können.

täuschen
quelle
4
Natürlich können Sie in JSON auch Nicht-Latin1-Zeichen mit Escape-Sequenzen wie darstellen \u20AC.
Dan04
31
Gemäß dem Standard für json dürfen Sie latin1 nicht für die Codierung des Inhalts verwenden. JSON-Inhalte müssen als Unicode codiert sein, sei es UTF-8, UTF-16 oder UTF-32 (Big oder Little Endian).
Daniel Luna
20
Es gibt keinen Zeichensatzparameter für application / json.
Julian Reschke
7
@ DanielLuna ist richtig, application/jsonmuss in einem der UCS-Transformationsformate sein. Da die ersten vier Bytes von JSON begrenzt sind, können Sie immer erkennen, ob es sich um 8, 16 oder 32 handelt, und um die Endianität.
Jason Coco
4
Ereignis, wenn es redundant ist, möchten Sie möglicherweise charset=utf-8aus Sicherheitsgründen einschließen : github.com/shieldfy/API-Security-Checklist/issues/25
manuc66
143

Um die Behauptung von @ deceze zu untermauern, dass die Standard-JSON-Codierung UTF-8 ist ...

Von IETF RFC4627 :

JSON-Text MUSS in Unicode codiert sein. Die Standardcodierung ist UTF-8.

Da die ersten beiden Zeichen eines JSON-Textes immer ASCII-Zeichen sind [RFC0020], kann bestimmt werden, ob ein Oktettstrom UTF-8, UTF-16 (BE oder LE) oder UTF-32 (BE oder LE) ist. indem Sie das Muster der Nullen in den ersten vier Oktetten betrachten.

      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
quelle
12
Es ist immer hilfreich, sich JSON als Binärformat und nicht als Textformat vorzustellen.
Sulthan
2
Nachdem RFC4627 von RFC7159 überholt wurde, der besagt, dass der Stammwert eine Zeichenfolge sein kann (im expliziten Gegensatz zur vorherigen Spezifikation), wie wird dies jetzt implementiert? Die Spezifikation ist in dieser Hinsicht vage und sagt nur, dass drei Codierungen erlaubt sind, aber nicht, wie man sie unterscheiden soll.
Fabio Beltramini
4
@FabioBeltramini Das Obige sollte weiterhin gelten, da eine Zeichenfolge in JSON keine wörtlichen Nullzeichen enthält (Nullen in JSON müssten mit einer numerischen Escape-Sequenz codiert werden, dh "\u0000").
Thomasrutter
3
Tatsächlich hat das zweite Zeichen in UTF-16xx in diesem Fall möglicherweise keine NULL, aber es ist weiterhin möglich, die Codierung aus den anderen Bytes zu bestimmen: xx 00 00 00ist immer noch UTF-32LE und xx 00 xx xxist immer noch UTF-16LE, 00 xx xx xxist immer noch UTF-16BE.
Thomasrutter
20

Beachten Sie, dass IETF RFC4627 durch IETF RFC7158 ersetzt wurde . In Abschnitt [8.1] wird der zuvor von @Drew zitierte Text zurückgezogen, indem gesagt wird:

Implementations MUST NOT add a byte order mark to the beginning of a JSON text.
Alex
quelle
Die Annahme gilt jedoch weiterhin, da jeder gültige JSON weiterhin mit zwei ASCII-Zeichen beginnt.
Larsing
Ein Zeichen, weil eine einzelne Ziffer eine gültige JSON-Datei ist
Nayuki
0

Ich stimme @deceze genau zu, aber ich möchte diesen Teil der Frage "Ich erhalte einen Fehler vom Dienst" entwickeln.

Wir bekommen diese Art von Fehlern als http 415

HTTP 415 Nicht unterstützter Medientypfehler

Der HTTP 415-Client-Fehlerantwortcode für nicht unterstützte Medientypen gibt an, dass der Server die Anforderung nicht akzeptiert, da das Nutzdatenformat in einem nicht unterstützten Format vorliegt.

Das Formatproblem kann auf den angegebenen Inhaltstyp oder die Inhaltscodierung der Anforderung oder auf die direkte Überprüfung der Daten zurückzuführen sein.

Mit anderen Worten, wie in https://stackoverflow.com/a/22643964/914284 dieses Beispiel zu sehen.

  • Wir müssen den richtigen Inhaltstyp festlegen und den richtigen Inhaltstyp akzeptieren (siehe Inhaltstyp hinzufügen: application / json und Akzeptieren: application / json). Andernfalls wird die Standardeinstellung übernommen
Hamit YILDIRIM
quelle
0

Die Implementierung von Dart http verarbeitet die Bytes dank dieses "charset = utf-8". Ich bin sicher, dass mehrere Implementierungen dies unterstützen, um den Fallback-Zeichensatz "latin-1" beim Lesen der Bytes aus der Antwort zu vermeiden. In meinem Fall verliere ich das Format der Antworttextzeichenfolge vollständig, daher muss ich die Bytecodierung manuell in utf8 durchführen oder diesen "inneren" Headerparameter zur API-Antwort meines Servers hinzufügen.

Roipeker
quelle
0

Ich habe HttpClient verwendet und den Antwortheader mit dem Inhaltstyp zurückgegeben application/json. Ich habe Zeichen wie Fremdsprachen oder Symbole verloren, die Unicode verwendeten, da HttpClient standardmäßig ISO-8859-1 ist . Seien Sie also so explizit wie möglich, wie von @WesternGun erwähnt, um mögliche Probleme zu vermeiden.

Es gibt keine Möglichkeit, dass der Server den angeforderten Header-Zeichensatz ( method.setRequestHeader("accept-charset", "UTF-8");) für mich nicht verarbeitet , und ich musste Antwortdaten als Zeichenbytes abrufen und sie mit UTF-8 in einen String konvertieren. Es wird daher empfohlen, explizit zu sein und die Annahme eines Standardwerts zu vermeiden.

Tri Nguyen
quelle