JSON文字エンコード-UTF-8はブラウザで十分にサポートされていますか、それとも数値エスケープシーケンスを使用する必要がありますか?


89

私はjsonを使用してそのリソースを表すWebサービスを作成していますが、jsonをエンコードするための最良の方法について考えるのに少し行き詰まっています。json rfc(http://www.ietf.org/rfc/rfc4627.txt)を読むと、推奨されるエンコーディングがutf-8であることが明らかです。ただし、rfcは、文字を指定するための文字列エスケープメカニズムについても説明しています。これは通常、非ASCII文字をエスケープするために使用され、それによって結果のutf-8が有効なASCIIになると思います。

したがって、ASCII以外のUnicode文字(コードポイント)を含むjson文字列があるとします。私のWebサービスはそれをutf-8エンコードして返す必要がありますか、それともすべての非ASCII文字をエスケープして純粋なASCIIを返す必要がありますか?

ブラウザでjsonpまたはevalを使用して結果を実行できるようにしたいと思います。それは決定に影響しますか?utf-8に対するさまざまなブラウザのjavascriptサポートに関する私の知識が不足しています。

編集:結果をエンコードする方法に関する私の主な関心事は、実際には結果のブラウザー処理に関するものであることを明確にしたいと思いました。私が読んだことは、特にJSONPを使用する場合、ブラウザーがエンコードに敏感である可能性があることを示しています。この件に関して本当に良い情報が見つからなかったので、何が起こるかを確認するためにいくつかのテストを開始する必要があります。理想的には、必要ないくつかの文字のみをエスケープし、utf-8だけで結果をエンコードしたいと思います。

回答:


88

JSON仕様で、デコーダーによるUTF-8サポートが必要です。その結果、すべてのJSONデコーダーは、数値エスケープシーケンスを処理できるのと同じようにUTF-8を処理できます。これはJavascriptインタープリターにも当てはまります。つまり、JSONPはUTF-8でエンコードされたJSONも処理します。

JSONエンコーダーが代わりに数値エスケープシーケンスを使用する機能は、より多くの選択肢を提供します。数値エスケープシーケンスを選択する理由の1つ、エンコーダーと目的のデコーダーの間のトランスポートメカニズムバイナリセーフでない場合です。

もうあなたは数値エスケープシーケンスを使用することをお勧めします理由ストリームに登場する特定の文字を防ぐためである、など<&および"JSONコードが配置されている場合、HTMLまたはブラウザにエスケープせずにHTMLシーケンスとして解釈することができる、誤ってHTMLとして解釈します。これは、HTMLインジェクションまたはクロスサイトスクリプティングに対する防御になります(注:"およびを含む一部の文字はJSONでエスケープする必要があります\)。

PHPのJSONの実装を含む一部のフレームワークは、ASCII以外の文字に対して、常にエンコーダ側で数値エスケープシーケンスを実行します。これは、制限されたトランスポートメカニズムなどとの最大の互換性を目的としています。ただし、これは、JSONデコーダーにUTF-8に問題があることを示すものとして解釈されるべきではありません。

だから、私はあなたがこのようにどちらを使うかを決めることができると思います:

  • エンコーダとデコーダ間の保存または転送方法がバイナリセーフでない場合を除き、UTF-8を使用してください。

  • それ以外の場合は、数値のエスケープシーケンスを使用します。


1
「すべてのJSONデコーダーはUTF-8を処理できます」これはブラウザーにも当てはまりますが、標準で要求されているからといって、JSONをデコードするすべてのソフトウェアがUTF-8をサポートしているわけではありません。
MichaelMior19年

7
「すべてのJSONデコーダーはUTF-8を処理できます」は文字通り真実です。何かがUTF-8を受け入れることができない場合、それはJSONデコーダーではありません。JSONデコーダーに似ているかもしれませんが、間違いなく1つではありません。
thomasrutter

使用しているJSONデコーダーの定義によって異なりますが、公平な点です:)
MichaelMior19年

RFC 8259がUTF-8サポートを必須として指定している理由は、それが世界で標準化されているものだからです。以前の廃止された仕様では、文字列はUnicodeとして定義されていましたが、どのエンコーディングを指定していませんでした。とにかくUTF-8で標準化された実装と、更新された仕様はそれを反映しています。
thomasrutter

私の知る限り、UTF-8のサポートは、特定のソフトウェアのRFCで必須として指定されていません。UTF-8についての唯一の言及は、クローズドシステムの外部で交換されるJSONのエンコーディングとして使用する必要があるということです。これは、すべてのJSONデコーダー(RFCで使用されていない言語)がUTF-8をサポートする必要があることを意味するものではありません。
MichaelMior19年

17

そこで問題が発生しました。「é」のような文字で文字列をJSONエンコードすると、「\ u00e9」を返すIEを除いて、すべてのブラウザが同じ「é」を返します。

次に、PHP json_decode()では、「é」が見つかると失敗するため、Firefox、Opera、Safari、Chromeの場合、json_decode()の前にutf8_encode()を呼び出す必要があります。

注:私のテストでは、IEとFirefoxはネイティブJSONオブジェクトを使用しており、他のブラウザーはjson2.jsを使用しています。


10
おそらくあなたはutf8_encode()php.net / manual / en / function.utf8
Binyamin

4
IEがそれをデコードできない場合は、使用しているJSONデコーダーのバグです。すべてのJSONデコーダーは、エンコードされたフォームを正常にデコードする必要があります。そうでない場合、JSONデコーダーではありません。éがエスケープされていないjson_decode()の問題については、フィードしているテキストがUTF-8ではない可能性があります。PHPは通常、他の多くの関数でUTF-8を想定していませんが、JSONデコーダーは常にUTF-8を想定しています。他にも、エスケープされていないものを含めて画面上で同じように見える文字エンコードがありますが、UTF-8ではありません。\ uXXXX形式でのエンコードは、これに対する回避策です。
thomasrutter 2013年

つまり、JSONは合法的に任意のUnicodeエンコーディング(UTF-8、UTF-16 BE / LE、UTF32 BE / LE、バイトオーダーマーカーの有無にかかわらず)で提供されます。また、ASCIIはUTF-8のサブセットであるため、ASCIIで提供することもできます。たとえば、パーサーがUTF-32を受け入れるかどうかはわかりません。
gnasher729 2016

1
これは正しいことであり、パーサーはUTF-8以外のものをサポートする必要はありません。仕様から:「JSONテキストはUTF-8、UTF-16、またはUTF-32でエンコードする必要があります。デフォルトのエンコードはUTF-8であり、UTF-8でエンコードされたJSONテキストは相互運用可能です。最大数の実装で正常に読み取られます。他のエンコーディング(UTF-16やUTF-32など)のテキストを正常に読み取れない実装が多数あります。実装では、JSONテキストの先頭にバイトオーダーマークを追加してはなりません。 「」
thomasrutter 2017年

@thomasrutter引用した仕様は古いです。現在の仕様は言う: " JSONテキストはUTF-8を使用してエンコードされなければならない、閉じた生態系の一部ではないシステム間で交換JSONテキストを送信するときにJSONの前の仕様はUTF-8を使用することを必要としていないが、大多数。 JSONベースのソフトウェア実装の多くは、相互運用性を実現する唯一のエンコーディングである範囲で、UTF-8エンコーディングを使用することを選択しました。実装は、ネットワーク送信の先頭にバイトオーダーマーク(U + FEFF)を追加してはなりません。 JSONテキスト。 "
RemyLebeau19年

12

ASCIIはもう含まれていません。UTF-8エンコーディングを使用するということは、ASCIIエンコーディングを使用していないことを意味します。エスケープメカニズムを使用する必要があるのは、RFCの内容です。

エスケープする必要のある文字(引用符、円記号、および制御文字(U +0000からU + 001F))を除いて、すべてのUnicode文字を引用符で囲むことができます。


1
あなたが提供したその引用を読むと、すべてのユニコード文字をエスケープする必要はなく、いくつかの特殊文字だけをエスケープする必要があることがわかります。ただし、結果をエンコードする必要があります(できればutf-8を使用)。したがって、問題は、「utf-8エンコーディングの場合、なぜ通常のUnicode文字をエスケープするのか」ということです。
schickb 2009

また、ASCIIでエンコードされた文字列は、utf-8の純粋なサブセットです。すべての非ASCII文字にjsonのエスケープを使用すると、結果はasciiになり、したがってutf-8になります。さまざまなjsonライブラリ(python simplejsonなど)には、ASCII結果を強制するモードがあります。おそらくブラウザでの実行のような理由があると思います。
schickb 2009

通常のUnicode文字をわざわざエスケープするのは、文字列などのメタ文字であるコンテキストです。(私が引用したRFCチャンクは文字列に関するものです。申し訳ありませんが、それについては明確ではありませんでした。)常にASCII出力を行う必要はありません。壊れたブラウザでデバッグするのはそれだけだと思います。
カオス

7

私も同じ問題に直面していました。わたしにはできる。こちらをご確認ください。

json_encode($array,JSON_UNESCAPED_UNICODE);

上記はPHPであることに注意してください。これは、質問がPHP固有のものではなく、PHPを使用しない可能性のあるWebサービスについてのみ説明しているためです(古い読者はまだ覚えているかもしれませんが…)
ntninja

1

json rfc(http://www.ietf.org/rfc/rfc4627.txt)を読むと、推奨されるエンコーディングがutf-8であることが明らかです。

参考までに、RFC4627は公式のJSON仕様ではなくなりました。2014年にRFC7159によって廃止され、2017年に現在の仕様であるRFC8259によって廃止されました

RFC8259は次のように述べています。

8.1。文字コード

クローズドエコシステムの一部ではないシステム間で交換されるJSONテキストは、UTF-8を使用してエンコードする必要があります[RFC3629]

JSONの以前の仕様では、JSONテキストを送信するときにUTF-8を使用する必要はありませんでした。ただし、JSONベースのソフトウェア実装の大部分は、相互運用性を実現する唯一のエンコーディングである限り、UTF-8エンコーディングを使用することを選択しています。

実装では、ネットワークで送信されるJSONテキストの先頭にバイトオーダーマーク(U + FEFF)を追加してはなりません(MUSTNOT)。相互運用性の観点から、JSONテキストを解析する実装は、バイトオーダーマークの存在をエラーとして扱うのではなく無視してもよい[MAY]。


0

écharでも同様の問題が発生しました...「フィードしているテキストがUTF-8ではない可能性があります」というコメントはおそらくここのマークに近いと思います。私のインスタンスのデフォルトの照合順序は、utf8に気づいて変更するまでは別のものだったと感じています...問題はデータがすでに存在しているため、変更したときにデータが変換されたかどうかわからないため、mysqlで正常に表示されますワークベンチ。最終結果は、phpがデータをjsonエンコードせず、falseを返すだけです。私の問題を引き起こしているサーバーとしてどのブラウザを使用しているかは関係ありません。この文字が存在する場合、phpはデータをutf8に解析しません。私が言うように、データが存在した後にスキーマをutf8に変換したことが原因なのか、それとも単なるphpのバグが原因なのかはわかりません。この場合、json_encode(utf8_encode($string));

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.