Кодування символів JSON - чи підтримується UTF-8 браузерами чи мені слід використовувати числові екрануючі послідовності?


89

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

Отже, припустимо, у мене є рядок json, який містить символи Unicode (кодові точки), які не є ascii. Чи повинен мій веб-сервіс просто кодувати utf-8 і повертати його, чи він повинен уникати всіх цих не-ascii символів і повертати чистий ascii?

Я хотів би, щоб браузери могли виконувати результати за допомогою jsonp або eval. Чи впливає це на рішення? Мені не відомо про підтримку різних браузерів javascript для utf-8.

EDIT: Я хотів пояснити, що моє головне занепокоєння щодо того, як кодувати результати, насправді полягає в обробці результатів у браузері. Те, що я прочитав, вказує на те, що браузери можуть бути чутливими до кодування, зокрема, використовуючи JSONP. Я не знайшов жодної справді хорошої інформації з цього питання, тому мені доведеться почати тестування, щоб побачити, що станеться. В ідеалі я хотів би уникати лише тих кількох символів, які потрібні, і просто utf-8 кодував результати.

Відповіді:


88

Специфікація JSON вимагає підтримки декодерів UTF-8. Як результат, усі декодери JSON можуть обробляти UTF-8 так само, як і обробляти числові послідовності екрану. Це також стосується інтерпретаторів Javascript, що означає, що JSONP також буде обробляти кодований UTF-8 JSON.

Можливість використання кодерами JSON числових послідовностей екранування просто пропонує вам більше вибору. Однією з причин, по якій ви можете обрати числові послідовності втечі, є транспортний механізм між ними вашим кодером та передбачуваним декодером не є двійково безпечним.

Ще однією причиною, за якою вам може знадобитися використовувати числові екрануючі послідовності, є запобігання появі певних символів у потоці, таких як <, &і ", які можуть бути інтерпретовані як послідовності HTML, якщо код JSON розміщений без переходу в HTML або браузер неправильно інтерпретує його як HTML . Це може бути захистом від ін'єкції HTML або міжсайтових сценаріїв (примітка: деякі символи ПОВИННІ уникати в JSON, включаючи "та \).

Деякі фреймворки, включаючи реалізацію JSON на PHP, завжди виконують числові екрануючі послідовності на стороні кодера для будь-якого символу за межами ASCII. Це призначено для максимальної сумісності з обмеженими транспортними механізмами тощо. Однак це не слід інтерпретувати як ознаку того, що декодери JSON мають проблеми з UTF-8.

Отже, я думаю, ви могли б просто вирішити, який із них використовувати таким чином:

  • Просто використовуйте UTF-8, якщо ваш спосіб зберігання або транспортування між кодером і декодером не є бінарним.

  • В іншому випадку використовуйте числові екрануючі послідовності.


1
"всі декодери JSON можуть обробляти UTF-8" Хоча це стосується браузерів, але те, що стандарт вимагає, це не означає, що все програмне декодування JSON підтримує UTF-8.
Майкл Міор

7
"Усі декодери JSON можуть обробляти UTF-8" буквально правда. Якщо щось не може прийняти UTF-8, це не декодер JSON. Це може бути схоже на декодер JSON, але це точно не один.
thomasrutter

Думаю, це залежить від того, яке визначення декодера JSON ви використовуєте, але справедливо: :)
Майкл Міор

Причиною, через яку RFC 8259 визначає підтримку UTF-8 як обов’язкову, є те, що це те, що стандартизував світ. Попередні застарілі специфікації визначали рядки як Unicode, але не вказували, яке кодування; впровадження, стандартизовані для UTF-8, і оновлена ​​специфікація це відображає.
thomasrutter

Підтримка UTF-8 не вказана як обов’язкова в цьому RFC для будь-якого конкретного програмного забезпечення, наскільки я можу зрозуміти. Єдина згадка про UTF-8 полягає в тому, що він повинен використовуватися як кодування для JSON, що обмінюється поза закритою системою. Це не означає, що всі декодери JSON (мова, яка не використовується в RFC) повинні підтримувати UTF-8.
Michael Mior

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

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) на початок мережевої передачі Текст JSON ".
Ремі Лебо,

12

ASCII в ньому вже немає. Використання кодування UTF-8 означає, що ви не використовуєте кодування ASCII. Для чого слід використовувати механізм виходу, це те, що говорить RFC:

Усі символи Unicode можуть бути розміщені в лапках, за винятком символів, які потрібно екранувати: лапки, зворотний солідус та контрольні символи (U + 0000 до U + 001F)


1
Прочитавши цитату, яку ви надали, ви побачите, що вам не потрібно уникати всіх символів Юнікоду, лише декілька спеціальних символів. Але вам потрібно закодувати результати (бажано за допомогою utf-8). Тож питання в тому: "Навіщо турбуватись, уникаючи звичайних символів Unicode, якщо ви кодуєте utf-8".
schickb

Крім того, кодований рядок ascii є чистою підмножиною utf-8. Якщо я використовую json-екранування для всіх символів, які не є ascii, результат буде ascii - і, отже, utf-8. Різні бібліотеки json (наприклад, python simplejson) мають режими, щоб примусити результати ascii. Я припускаю, з якоїсь причини, як, можливо, виконання у браузерах.
schickb

Коли ви турбуєтесь, уникаючи звичайних символів Unicode, ви перебуваєте в контексті, де вони є метасимволами, як рядки. (Частка 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.

FYI, 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));

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.