Що означає "Тип вмісту: application / json; charset = utf-8 ”насправді означає?


284

Коли я роблю запит POST з тілом JSON до своєї служби REST, я включаю Content-type: application/json; charset=utf-8в заголовок повідомлення. Без цього заголовка я отримую помилку від служби. Я також можу успішно використовувати Content-type: application/jsonбез ;charset=utf-8порції.

Що саме робить charset=utf-8? Я знаю, що він вказує кодування символів, але сервіс працює без нього. Чи обмежує це кодування символи, які можуть бути в тілі повідомлення?



8
Інтригуюче, згідно з реєстрацією засобів масової інформації IANAapplication/json , він взагалі не є підтримуваним charsetпараметром, хоча він часто надається на практиці.
Uux

1
I know it specifies the character encoding but the service works fine without it."Робота" не завжди означає, що існуючий код / ​​конфігурація є найбільш правильним способом, який охоплює всі кутові випадки, щоб зробити одну справу ". Це залежить від усіх конвенцій та припущень, які можуть не працювати за інших обставин. Для мене особисто я завжди намагаюся бути максимально чітким.
WesternGun

3
Надіслати параметр "charset" невірно та безглуздо. Див. RFC 8259, Розділ 11, останнє речення.
Решке

Відповіді:


283

Заголовок просто позначає, у чому вміст закодовано. Не обов’язково можна вивести тип вмісту із самого вмісту, тобто не можна просто обов’язково дивитися на вміст і знати, що з ним робити. Ось для чого і заголовки HTTP, вони повідомляють одержувачу, для якого типу вмісту вони (нібито) мають справу.

Content-type: application/json; charset=utf-8позначає вміст у форматі JSON, кодованому в кодуванні символів UTF-8. Позначення кодування є дещо зайвим для JSON, оскільки типовим (лише?) Кодуванням для JSON є UTF-8. Тому в цьому випадку сервер, що приймає, очевидно, щасливий, знаючи, що він має справу з JSON, і передбачає, що кодування за замовчуванням є UTF-8, тому він працює з заголовком або без нього.

Чи обмежує це кодування символи, які можуть бути в тілі повідомлення?

Ні. Ви можете надсилати все, що завгодно, в заголовок і тіло. Але, якщо вони не збігаються, ви можете отримати неправильні результати. Якщо ви вказали в заголовку, що вміст кодується UTF-8, але ви фактично надсилаєте вміст, кодований Latin1, приймач може видавати дані про сміття, намагаючись інтерпретувати дані, кодовані Latin1, як UTF-8. Якщо, звичайно, ви вказуєте, що ви надсилаєте кодовані дані Latin1, і ви насправді так робите, тоді так, ви обмежені 256 символами, які ви можете кодувати в Latin1.


4
Звичайно, в JSON ви все ще можете представляти символи, що не є латинськими1, використовуючи схожі послідовності \u20AC.
dan04

31
Згідно стандарту для json, вам фактично заборонено використовувати latin1 для кодування вмісту. Вміст JSON повинен бути закодований як унікод, будь то UTF-8, UTF-16 або UTF-32 (великий або маленький ендіан).
Даніель Луна

20
Параметр charset у застосуванні / json не існує.
Юліан Решке

7
@DanielLuna має рацію, application/jsonмає бути в одному з форматів перетворення ucs. Крім того, оскільки перші чотири байти JSON обмежені, ви завжди можете сказати, чи це 8, 16 або 32 та його ендіантність.
Джейсон Коко

4
Подія, якщо вона зайва, ви можете включити charset=utf-8з міркувань безпеки: github.com/shieldfy/API-Security-Checklist/isissue/25
manuc66

143

Для обґрунтування твердження @ deceze про те, що кодування JSON за замовчуванням є UTF-8 ...

Від IETF RFC4627 :

Текст JSON ДОЛЖЕН бути закодований в Unicode. Кодування за замовчуванням - UTF-8.

Оскільки перші два символи тексту JSON завжди будуть символами ASCII [RFC0020], можна визначити, чи є потік октету UTF-8, UTF-16 (BE або LE) або UTF-32 (BE або LE) переглядаючи візерунок нулів у перших чотирьох октетах.

      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

12
Це завжди допомагає думати про JSON як двійковий формат, а не текстовий формат.
Султан

2
Тепер, коли RFC4627 застаріло за допомогою RFC7159, де зазначено, що кореневим значенням може бути рядок (явно на відміну від колишньої специфікації), як це зараз реалізовано? Специфікація у цьому плані розпливчаста і просто говорить, що дозволено три кодування, але не те, як слід їх диференціювати.
Фабіо Белтраміні

4
@FabioBeltramini Вищенаведене все-таки має місце, тому що рядок у JSON не міститиме жодних буквальних нульових символів (нулі в JSON повинні бути закодовані числовою послідовністю відходу, тобто "\u0000").
thomasrutter

3
Насправді другий символ у UTF-16xx може не мати NULL в цьому випадку, але все одно можна буде визначити кодування з інших байтів: xx 00 00 00все ще UTF-32LE і xx 00 xx xxвсе ще UTF-16LE, 00 xx xx xxвсе ще UTF-16BE.
thomasrutter

20

Зауважте, що IETF RFC4627 витіснив IETF RFC7158 . У розділі [8.1] він відкликає текст, цитований @Drew раніше, кажучи:

Implementations MUST NOT add a byte order mark to the beginning of a JSON text.

Припущення все ж зберігається, оскільки будь-який дійсний json все ще розпочнеться з двох символів ascii.
Ларсінг

Один символ, оскільки одна цифра є дійсним файлом JSON
Nayuki

0

Я точно погоджуюся з @deceze, але я хочу розробити цю частину питання "я отримую помилку від служби" ,

Ми отримуємо такі помилки, як http 415

Http 415 Непідтримувана помилка типу медіа

Код відповіді на помилку клієнта типу HTTP 415 непідтримуваного типу Media Media указує на те, що сервер відмовляється прийняти запит, оскільки формат корисної навантаження знаходиться у непідтримуваному форматі.

Проблема з форматом може бути пов’язана із вказаним запитом Тип вмісту або Кодування вмісту або в результаті прямої перевірки даних.

Іншими словами, такі, як видно з https://stackoverflow.com/a/22643964/914284 у цьому прикладі.

  • Ми повинні встановити правильний тип вмісту, і ми повинні прийняти правильний тип вмісту, як показано Додати Content-Type: application / json та Accept: application / json. В іншому випадку він буде вважати за замовчуванням

0

Процес впровадження Dart http байтів завдяки цьому "charset = utf-8", тому я впевнений, що кілька реалізацій там підтримують це, щоб уникнути "резервної" схеми "latin-1" під час читання байтів з відповіді. У моєму випадку я повністю втрачаю формат у рядку тіла відповіді, тому мені доведеться виконувати кодування байтів вручну, щоб utf8, або додати цей внутрішній параметр заголовка у відповідь API мого сервера.


0

Я використовував HttpClient і отримував заголовок відповіді з типом вмісту application/json, я втратив такі символи, як іноземні мови або символ, які використовували unicode, оскільки HttpClient за замовчуванням відповідає ISO-8859-1 . Отже, будьте явні, наскільки це можливо, як згадував @WesternGun, щоб уникнути будь-якої можливої ​​проблеми.

Немає можливості обробити те, що сервер не обробляє запитувану шапку заголовка ( method.setRequestHeader("accept-charset", "UTF-8");) для мене, і мені довелося отримати дані відповідей у ​​вигляді байтів малювання та перетворити їх у String за допомогою UTF-8. Отже, рекомендується бути явним і уникати припущення про значення за замовчуванням.

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