Кодировка символов JSON - хорошо ли UTF-8 поддерживается браузерами или мне следует использовать числовые escape-последовательности?

89

Я пишу веб-сервис, который использует json для представления своих ресурсов, и я немного зациклился на том, как лучше всего закодировать json. Читая json rfc ( http://www.ietf.org/rfc/rfc4627.txt ), становится ясно, что предпочтительной кодировкой является utf-8. Но RFC также описывает механизм экранирования строки для указания символов. Я предполагаю, что это обычно используется для экранирования символов, отличных от ascii, тем самым делая результирующий utf-8 действительным ascii.

Итак, допустим, у меня есть строка json, содержащая символы Юникода (кодовые точки), не относящиеся к ascii. Должен ли мой веб-сервис просто кодировать utf-8 и возвращать его, или он должен избегать всех этих символов, отличных от ascii, и возвращать чистый ascii?

Я бы хотел, чтобы браузеры могли выполнять результаты с помощью jsonp или eval. Влияет ли это на решение? Мне не хватает знаний о поддержке utf-8 в различных браузерах javascript.

РЕДАКТИРОВАТЬ: Я хотел уточнить, что моя основная забота о том, как кодировать результаты, на самом деле связана с обработкой результатов браузером. То, что я прочитал, указывает на то, что браузеры могут быть чувствительны к кодировке, в частности, при использовании JSONP. Я не нашел действительно хорошей информации по этому поводу, поэтому мне придется начать тестирование, чтобы увидеть, что произойдет. В идеале я хотел бы избежать только тех нескольких символов, которые требуются, и просто кодировать результаты utf-8.

Schickb
источник

Ответы:

88

Спецификация JSON требует, чтобы декодеры поддерживали UTF-8. В результате все декодеры JSON могут обрабатывать UTF-8 так же хорошо, как они могут обрабатывать числовые escape-последовательности. Это также относится к интерпретаторам Javascript, что означает, что JSONP также будет обрабатывать JSON в кодировке UTF-8.

Возможность кодировщиков JSON использовать вместо этого числовые escape-последовательности просто предлагает вам больший выбор. Одна из причин, по которой вы можете выбрать числовые escape-последовательности, заключается в том, что транспортный механизм между вашим кодировщиком и предполагаемым декодером не является двоично-безопасным.

Другая причина, по которой вы можете захотеть использовать числовые escape-последовательности, - это предотвратить появление определенных символов в потоке, таких как <, &и ", которые могут быть интерпретированы как последовательности HTML, если код JSON помещен без экранирования в HTML или браузер ошибочно интерпретирует его как HTML. . Это может быть защитой от внедрения HTML или межсайтового скриптинга (примечание: некоторые символы ДОЛЖНЫ быть экранированы в JSON, включая "и\ ).

Некоторые фреймворки, включая реализацию JSON в PHP, всегда выполняют числовые escape-последовательности на стороне кодировщика для любого символа за пределами ASCII. Это предназначено для максимальной совместимости с ограниченными транспортными механизмами и т.п. Однако это не следует интерпретировать как указание на то, что декодеры JSON имеют проблемы с UTF-8.

Итак, я думаю, вы просто можете решить, что использовать следующим образом:

  • Просто используйте UTF-8, если ваш метод хранения или передачи между кодировщиком и декодером не является двоично-безопасным.

  • В противном случае используйте числовые escape-последовательности.

Thomasrutter
источник
1
«все декодеры JSON могут обрабатывать UTF-8». Хотя это верно для браузеров, только потому, что этого требует стандарт, не означает, что все программные декодеры JSON поддерживают UTF-8.
Michael Mior
7
«Все декодеры JSON могут обрабатывать UTF-8» буквально правда. Если что-то не может принять UTF-8, это не декодер JSON. Он может быть похож на декодер JSON, но определенно не таковой.
thomasrutter 04
Думаю, это зависит от того, какое определение декодера JSON вы используете, но справедливо :)
Майкл Майор
Причина, по которой RFC 8259 определяет поддержку UTF-8 как обязательную, заключается в том, что это то, что стандартизировано во всем мире. Предыдущие устаревшие спецификации определяли строки как Unicode, но не указывали, какая кодировка; реализации, в любом случае стандартизированные для UTF-8, и обновленная спецификация это отражает.
thomasrutter 04
Насколько я могу судить, поддержка UTF-8 не указана как обязательная в этом RFC для какого-либо конкретного программного обеспечения. Единственное упоминание об UTF-8 заключается в том, что он должен использоваться в качестве кодировки для JSON, которым обмениваются вне закрытой системы. Это не означает, что все декодеры JSON (язык, не используемый в RFC) должны поддерживать UTF-8.
Michael Mior 05
17

У меня там была проблема. Когда я JSON кодирую строку с таким символом, как «é», все браузеры будут возвращать то же «é», за исключением IE, который вернет «\ u00e9».

Затем с PHP json_decode () он не сработает, если найдет «é», поэтому для Firefox, Opera, Safari и Chrome я должен вызвать utf8_encode () перед json_decode ().

Примечание: в моих тестах IE и Firefox используют собственный объект JSON, другие браузеры используют json2.js.

Тим Тисдалл
источник
10
Вероятно, вы имели в виду utf8_encode(), php.net/manual/en/function.utf8-encode.php
Биньямин
4
Если IE не может его декодировать, это ошибка любого используемого вами декодера JSON. Все декодеры JSON должны успешно декодировать закодированную форму, в противном случае они не являются декодерами JSON. Что касается вашей проблемы с json_decode () с неэкранированным é, возможно, текст, который вы ему передаете, не UTF-8. Декодеры JSON всегда предполагают UTF-8, даже реализация PHP, хотя PHP обычно не использует UTF-8 во многих других функциях. Существуют и другие кодировки символов, которые могут включать é без экранирования и выглядеть идентично на экране, но не являются UTF-8. Кодирование в форме \ uXXXX - это обходной путь.
thomasrutter
Просто говорю: JSON может иметь любую кодировку Unicode (UTF-8, UTF-16 BE / LE, UTF32 BE / LE, с маркером порядка байтов или без него). А поскольку ASCII является подмножеством UTF-8, он также может входить в ASCII. Принимают ли парсеры, например, UTF-32, я не знаю.
gnasher729 01
1
Это правильно, и парсеры не обязаны поддерживать что-либо, кроме UTF-8. Из спецификации: «Текст JSON ДОЛЖЕН быть закодирован в UTF-8, UTF-16 или UTF-32. Кодировка по умолчанию - UTF-8, а тексты JSON, закодированные в UTF-8, совместимы в том смысле, что они будут могут быть успешно прочитаны максимальным числом реализаций; существует множество реализаций, которые не могут успешно читать тексты в других кодировках (например, UTF-16 и UTF-32). Реализации НЕ ДОЛЖНЫ добавлять отметку порядка байтов в начало текста JSON. "
thomasrutter
@thomasrutter Указанная вами спецификация устарела. В текущей спецификации говорится: « Текст JSON, которым обмениваются системы, которые не являются частью закрытой экосистемы, ДОЛЖЕН быть закодирован с использованием UTF-8. Предыдущие спецификации JSON не требовали использования UTF-8 при передаче текста JSON. Однако подавляющее большинство программных реализаций на основе JSON выбрали кодировку UTF-8 в той мере, в какой это единственная кодировка, которая обеспечивает взаимодействие. Реализации НЕ ДОЛЖНЫ добавлять отметку порядка байтов (U + FEFF) в начало передаваемого по сети Текст в
Реми Лебо,
12

ASCII в нем больше нет. Использование кодировки UTF-8 означает, что вы не используете кодировку ASCII. В RFC говорится, что вам следует использовать механизм экранирования:

Все символы Unicode могут быть помещены в кавычки, за исключением символов, которые должны быть экранированы: кавычки, обратная косая черта и управляющие символы (от U + 0000 до U + 001F)

хаос
источник
1
Если вы прочитаете эту цитату, которую вы предоставили, вы увидите, что вам не нужно экранировать все символы Юникода, а только несколько специальных символов. Но от вас требуется закодировать результаты (желательно с помощью utf-8). Возникает вопрос: «Зачем нужно экранировать обычные символы Юникода, если вы кодируете utf-8».
schickb
Кроме того, строка в кодировке ascii является чистым подмножеством utf-8. Если я использую экранирование json для всех символов, отличных от ascii, результатом будет ascii - и, следовательно, utf-8. В различных библиотеках json (таких как python simplejson) есть режимы для принудительного вывода результатов ascii. Я предполагаю, что по какой-то причине, например, исполнение в браузерах.
schickb
Когда вы беспокоитесь об экранировании обычных символов Юникода, это в контекстах, где они являются метасимволами, такими как строки. (Приведенный мной фрагмент RFC касается строк; извините, это не совсем понятно.) Вам не нужно постоянно выводить ASCII; Думаю, это больше для отладки со сломанными браузерами.
хаос
7

Я столкнулся с той же проблемой. Меня устраивает. Пожалуйста, проверьте это.

json_encode($array,JSON_UNESCAPED_UNICODE);
Анкит Севадик
источник
Следует отметить, что вышеупомянутое относится к PHP, поскольку вопрос никоим образом не относится к PHP и касается только веб-службы, которая также может не использовать PHP (как старые из наших читателей, возможно, еще помнят…)
ntninja
1

Читая json rfc ( http://www.ietf.org/rfc/rfc4627.txt ), становится ясно, что предпочтительной кодировкой является utf-8.

К вашему сведению, RFC 4627 больше не является официальной спецификацией JSON. Он был отменен в 2014 году в соответствии с RFC 7159 , который затем был отменен в 2017 году в соответствии с RFC 8259 , который является текущей спецификацией.

RFC 8259 гласит:

8.1. Кодировка символов

Текст JSON, которым обмениваются системы, не являющиеся частью закрытой экосистемы, ДОЛЖЕН быть закодирован с использованием UTF-8 [RFC3629] .

Предыдущие спецификации JSON не требовали использования UTF-8 при передаче текста JSON. Однако подавляющее большинство программных реализаций на основе JSON решили использовать кодировку UTF-8 в той степени, в которой это единственная кодировка, которая обеспечивает взаимодействие.

Реализации НЕ ДОЛЖНЫ добавлять отметку порядка байтов (U + FEFF) в начало текста JSON, передаваемого по сети. В интересах взаимодействия реализации, анализирующие тексты JSON, МОГУТ игнорировать наличие отметки порядка байтов, а не рассматривать ее как ошибку.

Реми Лебо
источник
0

У меня была аналогичная проблема с é char ... Я думаю, что комментарий «возможно, что текст, который вы вводите, не UTF-8», вероятно, близок к отметке здесь. У меня такое чувство, что сортировка по умолчанию в моем экземпляре была чем-то другим, пока я не понял и не изменил на utf8 ... проблема в том, что данные уже были там, поэтому не уверен, преобразовал ли он данные или нет, когда я их изменил, отлично отображается в mysql верстак. Конечным результатом является то, что php не будет кодировать данные json, а просто вернет false. Неважно, какой браузер вы используете в качестве сервера, вызывающего мою проблему, php не будет анализировать данные в utf8, если этот символ присутствует. Как я говорю, не уверен, связано ли это с преобразованием схемы в utf8 после того, как данные присутствовали, или просто с ошибкой php. В этом случае используйтеjson_encode(utf8_encode($string));

Пол Смит
источник