Apa yang dilakukan “Jenis konten: aplikasi / json; charset = utf-8 ”benar-benar berarti?

284

Ketika saya membuat permintaan POST dengan tubuh JSON ke layanan REST saya, saya sertakan Content-type: application/json; charset=utf-8di header pesan. Tanpa tajuk ini, saya mendapatkan kesalahan dari layanan. Saya juga bisa berhasil menggunakan Content-type: application/jsontanpa ;charset=utf-8porsi.

Apa yang sebenarnya charset=utf-8dilakukan? Saya tahu itu menentukan pengkodean karakter tetapi layanan berfungsi dengan baik tanpa itu. Apakah penyandian ini membatasi karakter yang bisa berada di badan pesan?

DenaliHardtail
sumber
4
lihatlah hanselman.com/blog/…
Daniel Powell
8
Menariknya, menurut Registrasi Jenis Media IANAapplication/json , tampaknya tidak ada charsetparameter yang didukung sama sekali, meskipun sering diberikan dalam praktik.
Uux
1
I know it specifies the character encoding but the service works fine without it."berfungsi" tidak selalu berarti "kode / konfigurasi yang ada adalah cara paling benar yang mencakup semua kasus sudut untuk melakukan satu hal". Itu tergantung pada semua konvensi dan asumsi yang mungkin tidak berfungsi dalam keadaan lain. Bagi saya pribadi, saya selalu berusaha sejelas mungkin.
WesternGun
3
Mengirim parameter "charset" salah dan tidak berarti. Lihat RFC 8259, Bagian 11, kalimat terakhir.
Julian Reschke

Jawaban:

283

Header hanya menunjukkan konten yang dikodekan. Tidak mungkin untuk menyimpulkan jenis konten dari konten itu sendiri, yaitu Anda tidak bisa hanya melihat konten dan tahu apa yang harus dilakukan dengannya. Untuk itulah tajuk HTTP, mereka memberi tahu penerima jenis apa yang mereka hadapi.

Content-type: application/json; charset=utf-8menetapkan konten dalam format JSON, disandikan dalam pengkodean karakter UTF-8. Menentukan pengkodean agak berlebihan untuk JSON, karena pengkodean default (hanya?) Untuk JSON adalah UTF-8. Jadi dalam hal ini server penerima tampaknya senang mengetahui bahwa ia berurusan dengan JSON dan mengasumsikan bahwa pengkodean adalah UTF-8 secara default, itu sebabnya ia bekerja dengan atau tanpa header.

Apakah penyandian ini membatasi karakter yang bisa berada di badan pesan?

Tidak. Anda dapat mengirim apa pun yang Anda inginkan di tajuk dan isi. Tetapi, jika keduanya tidak cocok, Anda mungkin mendapatkan hasil yang salah. Jika Anda menentukan di header bahwa konten dikodekan UTF-8 tetapi Anda benar-benar mengirim konten terkode Latin1, penerima dapat menghasilkan data sampah, mencoba untuk menafsirkan data terkode Latin1 sebagai UTF-8. Jika tentu saja Anda menentukan bahwa Anda mengirim data yang disandikan Latin1 dan Anda benar-benar melakukannya, maka ya, Anda terbatas pada 256 karakter yang dapat Anda encode dalam Latin1.

tipuan
sumber
4
Tentu saja, di JSON Anda masih bisa mewakili karakter non-Latin1 menggunakan escape sequence seperti \u20AC.
dan04
31
Menurut standar untuk json, Anda sebenarnya tidak diizinkan menggunakan latin1 untuk penyandian konten. Konten JSON harus dikodekan sebagai unicode, baik itu UTF-8, UTF-16, atau UTF-32 (endian besar atau kecil).
Daniel Luna
20
Tidak ada parameter charset pada aplikasi / json.
Julian Reschke
7
@DanielLuna benar, application/jsonharus dalam salah satu format transformasi ucs. Juga, karena empat byte pertama JSON terbatas, Anda selalu dapat mengetahui apakah itu 8, 16, atau 32 dan daya tahannya.
Jason Coco
4
Acara jika mubazir, Anda mungkin ingin memasukkannya charset=utf-8untuk alasan keamanan: github.com/shieldfy/API-Security-Checklist/issues/25
manuc66
143

Untuk membuktikan klaim @ deceze bahwa penyandian JSON default adalah UTF-8 ...

Dari IETF RFC4627 :

Teks JSON AKAN dikodekan dalam Unicode. Pengkodean default adalah UTF-8.

Karena dua karakter pertama dari teks JSON akan selalu menjadi karakter ASCII [RFC0020], dimungkinkan untuk menentukan apakah aliran oktet adalah UTF-8, UTF-16 (BE atau LE), atau UTF-32 (BE atau LE) dengan melihat pola nol pada empat oktet pertama.

      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
Drew Noakes
sumber
12
Selalu membantu untuk memikirkan JSON sebagai format biner, bukan format teks.
Sulthan
2
Sekarang RFC4627 sudah usang oleh RFC7159, yang menyatakan bahwa nilai root mungkin berupa string (berbeda dengan spec sebelumnya), bagaimana ini sekarang diimplementasikan? Spesifikasinya tidak jelas dalam hal ini, dan hanya mengatakan bahwa tiga penyandian diperbolehkan, tetapi tidak bagaimana seseorang seharusnya membedakannya.
Fabio Beltramini
4
@FabioBeltramini Di atas masih harus tetap, karena string dalam JSON tidak akan berisi karakter null literal (nulls di JSON harus dikodekan dengan urutan melarikan diri numerik yaitu "\u0000").
thomasrutter
3
Sebenarnya karakter kedua dalam UTF-16xx mungkin tidak memiliki NULL dalam kasus itu, tetapi masih mungkin untuk menentukan pengkodean dari byte lain: xx 00 00 00masih UTF-32LE dan xx 00 xx xxmasih UTF-16LE, 00 xx xx xxmasih UTF-16BE.
thomasrutter
20

Perhatikan bahwa IETF RFC4627 telah digantikan oleh IETF RFC7158 . Di bagian [8.1] itu menarik kembali teks yang dikutip oleh @Drew dengan mengatakan:

Implementations MUST NOT add a byte order mark to the beginning of a JSON text.
Alex
sumber
Asumsi itu masih berlaku, karena setiap json yang valid masih akan mulai dengan dua karakter ascii.
Larsing
Satu karakter, karena satu angka adalah file JSON yang valid
Nayuki
0

Saya benar-benar setuju dengan @menerima tetapi saya ingin mengembangkan ini "Saya mendapatkan kesalahan dari layanan" pada pertanyaan,

Kami mendapatkan kesalahan seperti ini sebagai http 415

Http 415 Kesalahan tipe Media yang tidak didukung

Kode respons klien kesalahan Jenis Media HTTP 415 Tidak Didukung menunjukkan bahwa server menolak untuk menerima permintaan karena format payload dalam format yang tidak didukung.

Masalah format mungkin disebabkan oleh Jenis - Konten atau Pengodean-Konten yang diminta , atau sebagai hasil dari inspeksi data secara langsung.

Dengan kata lain seperti terlihat di https://stackoverflow.com/a/22643964/914284 contoh ini.

  • Kita harus mengatur tipe konten yang benar dan kita harus menerima tipe konten yang tepat seperti yang terlihat Tambahkan Tipe-Konten: application / json dan Accept: application / json. Kalau tidak, itu akan menganggap default
Hamit YILDIRIM
sumber
0

Implementasi Dart http memproses byte berkat "charset = utf-8", jadi saya yakin beberapa implementasi di luar sana mendukung hal ini, untuk menghindari charset fallback "latin-1" saat membaca byte dari respons. Dalam kasus saya, saya benar-benar kehilangan format pada string body respons, jadi saya harus melakukan enkode byte secara manual ke utf8, atau menambahkan parameter header "inner" pada respons API server saya.

roipeker
sumber
0

Saya menggunakan HttpClient dan mendapatkan header respons kembali dengan tipe konten application/json, saya kehilangan karakter seperti bahasa asing atau simbol yang menggunakan unicode karena HttpClient adalah default untuk ISO-8859-1 . Jadi, sejelas mungkin seperti yang disebutkan oleh @WesternGun untuk menghindari masalah yang mungkin terjadi.

Tidak ada cara menangani itu karena server tidak menangani charset ( method.setRequestHeader("accept-charset", "UTF-8");) header yang diminta ( ) untuk saya dan saya harus mengambil data respons sebagai draw bytes dan mengubahnya menjadi String menggunakan UTF-8. Jadi, disarankan untuk eksplisit dan menghindari asumsi nilai default.

Tri Nguyen
sumber