JSON-Zeichencodierung - Wird UTF-8 von Browsern gut unterstützt oder sollte ich numerische Escape-Sequenzen verwenden?

85

Ich schreibe einen Webservice, der json verwendet, um seine Ressourcen darzustellen, und ich bin ein bisschen festgefahren, wie ich den json am besten codieren kann. Beim Lesen des json rfc ( http://www.ietf.org/rfc/rfc4627.txt ) ist klar, dass die bevorzugte Codierung utf-8 ist. Der RFC beschreibt aber auch einen Mechanismus zum Entkommen von Zeichenfolgen zum Angeben von Zeichen. Ich gehe davon aus, dass dies im Allgemeinen verwendet wird, um Nicht-ASCII-Zeichen zu entkommen, wodurch das resultierende utf-8-ASCII gültig wird.

Nehmen wir also an, ich habe eine JSON-Zeichenfolge, die Unicode-Zeichen (Codepunkte) enthält, die keine ASCII-Zeichen sind. Sollte mein Webservice nur utf-8 codieren und zurückgeben, oder sollte er all diesen Nicht-ASCII-Zeichen entkommen und reines ASCII zurückgeben?

Ich möchte, dass Browser die Ergebnisse mit jsonp oder eval ausführen können. Beeinflusst das die Entscheidung? Mein Wissen über die Javascript-Unterstützung verschiedener Browser für utf-8 fehlt.

EDIT: Ich wollte klarstellen, dass mein Hauptanliegen beim Codieren der Ergebnisse wirklich die Browser-Handhabung der Ergebnisse ist. Was ich gelesen habe, weist darauf hin, dass Browser möglicherweise besonders bei Verwendung von JSONP empfindlich auf die Codierung reagieren. Ich habe keine wirklich guten Informationen zu diesem Thema gefunden, daher muss ich einige Tests durchführen, um zu sehen, was passiert. Im Idealfall möchte ich nur den wenigen erforderlichen Zeichen entkommen und nur utf-8 die Ergebnisse codieren.

schickb
quelle

Antworten:

84

Die JSON-Spezifikation erfordert UTF-8-Unterstützung durch Decoder. Infolgedessen können alle JSON-Decoder UTF-8 genauso gut verarbeiten wie die numerischen Escape-Sequenzen. Dies gilt auch für Javascript-Interpreter, was bedeutet, dass JSONP auch den UTF-8-codierten JSON verarbeitet.

Die Möglichkeit für JSON-Encoder, stattdessen die numerischen Escape-Sequenzen zu verwenden, bietet Ihnen nur mehr Auswahlmöglichkeiten. Ein Grund, warum Sie die numerischen Escape-Sequenzen wählen können, ist, wenn ein Transportmechanismus zwischen Ihrem Encoder und dem beabsichtigten Decoder nicht binärsicher ist.

Ein weiterer Grund , warum Sie wollen können numerische Escape - Sequenzen verwenden bestimmte Zeichen zu verhindern , in dem Strom erscheinen, wie <, &und ", die als HTML - Sequenzen interpretiert werden kann , wenn der JSON - Code ohne Flucht in HTML oder ein Browser interpretiert es falsch platziert ist als HTML . Dies kann eine Verteidigung gegen HTML-Injection oder Cross-Site-Scripting sein (Hinweis: Einige Zeichen MÜSSEN in JSON maskiert werden, einschließlich "und \).

Einige Frameworks, einschließlich der Implementierung von JSON durch PHP, führen für jedes Zeichen außerhalb von ASCII immer die numerischen Escape-Sequenzen auf der Encoderseite aus. Dies ist für maximale Kompatibilität mit begrenzten Transportmechanismen und dergleichen vorgesehen. Dies sollte jedoch nicht als Hinweis darauf interpretiert werden, dass JSON-Decoder ein Problem mit UTF-8 haben.

Ich denke, Sie könnten sich einfach so entscheiden:

  • Verwenden Sie einfach UTF-8, es sei denn, Ihre Speicher- oder Transportmethode zwischen Encoder und Decoder ist nicht binärsicher.

  • Verwenden Sie andernfalls die numerischen Escape-Sequenzen.

thomasrutter
quelle
1
"Alle JSON-Decoder können mit UTF-8 umgehen" Während dies für Browser gilt, bedeutet dies nicht, dass alle Software-Decodierungen, die JSON unterstützt, UTF-8 unterstützen, nur weil der Standard dies erfordert.
Michael Mior
7
"Alle JSON-Decoder können mit UTF-8 umgehen" ist buchstäblich wahr. Wenn etwas UTF-8 nicht akzeptieren kann, ist es kein JSON-Decoder. Es mag einem JSON-Decoder ähnlich sein, ist es aber definitiv nicht.
Thomasrutter
Ich denke, das hängt davon ab, welche Definition des JSON-Decoders Sie verwenden, aber fairer Punkt :)
Michael Mior
Der Grund, warum RFC 8259 die UTF-8-Unterstützung als obligatorisch spezifiziert, ist, dass dies das ist, worauf die Welt standardisiert. Frühere veraltete Spezifikationen definierten Zeichenfolgen als Unicode, gaben jedoch nicht an, welche Codierung verwendet wurde. Implementierungen, die ohnehin auf UTF-8 standardisiert sind, und die aktualisierte Spezifikation spiegeln dies wider.
Thomasrutter
Soweit ich das beurteilen kann, ist die UTF-8-Unterstützung in diesem RFC für eine bestimmte Software nicht als obligatorisch angegeben. Die einzige Erwähnung von UTF-8 ist, dass es als Codierung für JSON verwendet werden muss, das außerhalb eines geschlossenen Systems ausgetauscht wird. Dies bedeutet nicht, dass alle JSON-Decoder (eine Sprache, die im RFC nicht verwendet wird) UTF-8 unterstützen müssen.
Michael Mior
17

Ich hatte dort ein Problem. Wenn ich JSON eine Zeichenfolge mit einem Zeichen wie "é" codiere, gibt jeder Browser das gleiche "é" zurück, mit Ausnahme des IE, der "\ u00e9" zurückgibt.

Dann schlägt es mit PHP json_decode () fehl, wenn "é" gefunden wird. Für Firefox, Opera, Safari und Chrome muss ich utf8_encode () vor json_decode () aufrufen.

Hinweis: Bei meinen Tests verwenden IE und Firefox ihr natives JSON-Objekt, andere Browser verwenden json2.js.

Tim Tisdall
quelle
10
Wahrscheinlich meinten Sie utf8_encode(), php.net/manual/en/function.utf8-encode.php
Binyamin
4
Wenn der IE dies nicht dekodieren kann, liegt ein Fehler in dem von Ihnen verwendeten JSON-Decoder vor. Alle JSON-Decoder müssen das codierte Formular erfolgreich decodieren, oder sie sind keine JSON-Decoder. Bei Ihrem Problem mit json_decode () mit é unescaped ist es möglich, dass der Text, den Sie eingeben, nicht UTF-8 ist. JSON-Decoder übernehmen immer UTF-8, auch die PHP-Implementierung, obwohl PHP in vielen anderen Funktionen normalerweise nicht UTF-8 übernimmt. Es gibt andere Zeichenkodierungen, die ein ungehindertes é enthalten und auf dem Bildschirm identisch aussehen können, aber nicht UTF-8 sind. Die Codierung in \ uXXXX-Form ist eine Problemumgehung.
Thomasrutter
Nur zu sagen: JSON kann legal in jeder Unicode-Codierung (UTF-8, UTF-16 BE / LE, UTF32 BE / LE, mit oder ohne Byte-Ordnungsmarkierung) geliefert werden. Und da ASCII eine Teilmenge von UTF-8 ist, kann es auch in ASCII vorliegen. Ob Parser beispielsweise UTF-32 akzeptieren, weiß ich nicht.
gnasher729
1
Das ist richtig und Parser müssen nichts anderes als UTF-8 unterstützen. Aus der Spezifikation: "JSON-Text MUSS in UTF-8, UTF-16 oder UTF-32 codiert werden. Die Standardcodierung ist UTF-8, und JSON-Texte, die in UTF-8 codiert sind, sind in dem Sinne interoperabel, wie sie es werden." Es gibt viele Implementierungen, die Texte in anderen Codierungen (z. B. UTF-16 und UTF-32) nicht erfolgreich lesen können. Implementierungen dürfen am Anfang eines JSON-Textes KEINE Byte-Ordnungsmarke hinzufügen. ""
Thomasrutter
@thomasrutter Die von Ihnen angegebene Spezifikation ist alt. In der aktuellen Spezifikation heißt es: " JSON-Text, der zwischen Systemen ausgetauscht wird, die nicht Teil eines geschlossenen Ökosystems sind, MUSS mit UTF-8 codiert werden. Frühere Spezifikationen von JSON erforderten nicht die Verwendung von UTF-8 bei der Übertragung von JSON-Text. Die überwiegende Mehrheit jedoch von JSON-basierten Softwareimplementierungen haben sich für die Verwendung der UTF-8-Codierung entschieden, sofern dies die einzige Codierung ist, die Interoperabilität erreicht. Implementierungen dürfen am Anfang einer Netzwerkübertragung KEINE Byte-Ordnungsmarke (U + FEFF) hinzufügen JSON-Text. "
Remy Lebeau
12

ASCII ist nicht mehr drin. Die Verwendung der UTF-8-Codierung bedeutet, dass Sie keine ASCII-Codierung verwenden. Wofür Sie den Escape-Mechanismus verwenden sollten, ist das, was der RFC sagt:

Alle Unicode-Zeichen dürfen innerhalb der Anführungszeichen stehen, mit Ausnahme der Zeichen, die maskiert werden müssen: Anführungszeichen, umgekehrter Solidus und die Steuerzeichen (U + 0000 bis U + 001F).

Chaos
quelle
1
Wenn Sie das von Ihnen angegebene Zitat lesen, werden Sie feststellen, dass Sie nicht alle Unicode-Zeichen, sondern nur einige Sonderzeichen maskieren müssen. Sie müssen die Ergebnisse jedoch codieren (vorzugsweise mit utf-8). Die Frage lautet also: "Warum sollten Sie sich die Mühe machen, normalen Unicode-Zeichen zu entkommen, wenn Sie eine utf-8-Codierung verwenden?"
schickb
Außerdem ist eine ASCII-codierte Zeichenfolge eine reine Teilmenge von utf-8. Wenn ich jsons Escapezeichen für alle Nicht-ASCII-Zeichen verwende, ist das Ergebnis ASCII - und daher utf-8. Verschiedene json-Bibliotheken (wie python simplejson) haben Modi, um ASCII-Ergebnisse zu erzwingen. Ich nehme aus einem Grund an, wie vielleicht die Ausführung in Browsern.
schickb
Wenn Sie sich die Mühe machen, normalen Unicode-Zeichen zu entkommen, befinden Sie sich in Kontexten, in denen sie Metazeichen wie Zeichenfolgen sind. (In dem von mir zitierten RFC-Block geht es um Zeichenfolgen. Das war mir leider nicht klar.) Sie müssen nicht die ganze Zeit über ASCII ausgeben. Ich würde denken, das ist mehr für das Debuggen mit kaputten Browsern.
Chaos
7

Ich hatte das gleiche Problem. Für mich geht das. Bitte prüfen Sie das.

json_encode($array,JSON_UNESCAPED_UNICODE);
Ankit Sewadik
quelle
Es sollte beachtet werden, dass es sich bei dem oben genannten um PHP handelt, da die Frage in keiner Weise PHP-spezifisch ist und nur über Webdienste spricht , die möglicherweise auch kein PHP verwenden (wie die älteren unserer Leser sich vielleicht noch erinnern…)
ntninja
1

Beim Lesen des json rfc ( http://www.ietf.org/rfc/rfc4627.txt ) ist klar, dass die bevorzugte Codierung utf-8 ist.

Zu Ihrer Information, RFC 4627 ist nicht mehr die offizielle JSON-Spezifikation. Es wurde 2014 von RFC 7159 überholt , das 2017 von RFC 8259 , der aktuellen Spezifikation, überholt wurde .

RFC 8259 besagt:

8.1. Zeichenkodierung

JSON-Text, der zwischen Systemen ausgetauscht wird, die nicht Teil eines geschlossenen Ökosystems sind, MUSS mit UTF-8 [RFC3629] codiert werden .

Frühere Spezifikationen von JSON erforderten nicht die Verwendung von UTF-8 bei der Übertragung von JSON-Text. Die überwiegende Mehrheit der JSON-basierten Softwareimplementierungen hat sich jedoch für die Verwendung der UTF-8-Codierung entschieden, sofern dies die einzige Codierung ist, die Interoperabilität erreicht.

Implementierungen DÜRFEN KEIN Byte-Ordnungszeichen (U + FEFF) am Anfang eines im Netzwerk übertragenen JSON-Textes einfügen. Im Interesse der Interoperabilität können Implementierungen, die JSON-Texte analysieren, das Vorhandensein eines Byte-Ordnungszeichens ignorieren, anstatt es als Fehler zu behandeln.

Remy Lebeau
quelle
0

Ich hatte ein ähnliches Problem mit é char ... Ich denke, der Kommentar "Es ist möglich, dass der Text, den Sie eingeben, nicht UTF-8 ist" hier wahrscheinlich nahe an der Marke liegt. Ich habe das Gefühl, dass die Standardkollatierung in meiner Instanz etwas anderes war, bis ich erkannte und auf utf8 änderte. Das Problem ist, dass die Daten bereits vorhanden waren. Ich bin mir also nicht sicher, ob sie die Daten konvertiert haben oder nicht, wenn ich sie geändert habe. Wird in MySQL gut angezeigt Werkbank. Das Endergebnis ist, dass PHP die Daten nicht json codiert, sondern nur false zurückgibt. Egal welchen Browser Sie als Server verwenden, der mein Problem verursacht, PHP analysiert die Daten nicht nach utf8, wenn dieses Zeichen vorhanden ist. Wie ich schon sagte, nicht sicher, ob es an der Konvertierung des Schemas in utf8 liegt, nachdem Daten vorhanden waren oder nur an einem PHP-Fehler. In diesem Fall verwendenjson_encode(utf8_encode($string));

Paul Smith
quelle