Pengkodean karakter JSON - apakah UTF-8 didukung dengan baik oleh browser atau haruskah saya menggunakan urutan pelolosan numerik?

91

Saya menulis layanan web yang menggunakan json untuk mewakili sumber dayanya, dan saya agak terjebak memikirkan cara terbaik untuk menyandikan json. Membaca json rfc ( http://www.ietf.org/rfc/rfc4627.txt ) jelas bahwa pengkodean yang disukai adalah utf-8. Tetapi rfc juga menjelaskan mekanisme pelolosan string untuk menentukan karakter. Saya berasumsi ini umumnya akan digunakan untuk melarikan diri karakter non-ascii, sehingga membuat ascii yang valid utf-8.

Jadi katakanlah saya memiliki string json yang berisi karakter unicode (kode-poin) yang non-ascii. Haruskah webservice saya hanya mengkodekan utf-8 dan mengembalikannya, atau haruskah ia keluar dari semua karakter non-ascii dan mengembalikan ascii murni?

Saya ingin browser dapat menjalankan hasil menggunakan jsonp atau eval. Apakah itu mempengaruhi keputusan? Pengetahuan saya tentang berbagai dukungan javascript browser untuk utf-8 masih kurang.

EDIT: Saya ingin mengklarifikasi bahwa perhatian utama saya tentang cara menyandikan hasil sebenarnya tentang penanganan hasil di browser. Apa yang saya baca menunjukkan bahwa browser mungkin sensitif terhadap pengkodean khususnya saat menggunakan JSONP. Saya belum menemukan info yang benar-benar bagus tentang masalah ini, jadi saya harus mulai melakukan beberapa pengujian untuk melihat apa yang terjadi. Idealnya saya hanya ingin menghindari beberapa karakter yang diperlukan dan hanya menyandikan hasil utf-8.

schickb.dll
sumber

Jawaban:

89

Spesifikasi JSON memerlukan dukungan UTF-8 oleh dekoder. Hasilnya, semua dekoder JSON dapat menangani UTF-8 sebaik mereka dapat menangani urutan pelolosan numerik. Ini juga kasus untuk juru bahasa Javascript, yang berarti JSONP akan menangani JSON yang dikodekan UTF-8 juga.

Kemampuan pembuat enkode JSON untuk menggunakan urutan pelolosan numerik hanya menawarkan lebih banyak pilihan kepada Anda. Salah satu alasan Anda dapat memilih urutan pelolosan numerik adalah jika mekanisme pengangkutan di antara pembuat enkode dan dekoder yang dimaksud tidak aman biner.

Alasan lain Anda mungkin ingin menggunakan urutan pelolosan numerik adalah untuk mencegah karakter tertentu muncul di aliran, seperti <, &dan ", yang dapat ditafsirkan sebagai urutan HTML jika kode JSON ditempatkan tanpa keluar ke HTML atau browser salah mengartikannya sebagai HTML . Ini bisa menjadi pertahanan terhadap injeksi HTML atau skrip lintas situs (catatan: beberapa karakter HARUS di-escape di JSON, termasuk "dan \).

Beberapa framework, termasuk implementasi PHP dari JSON, selalu melakukan urutan escape numerik di sisi encoder untuk karakter apa pun di luar ASCII. Ini dimaksudkan untuk kompatibilitas maksimum dengan mekanisme transport terbatas dan sejenisnya. Namun, ini tidak boleh ditafsirkan sebagai indikasi bahwa dekoder JSON memiliki masalah dengan UTF-8.

Jadi, saya rasa Anda bisa memutuskan mana yang akan digunakan seperti ini:

  • Cukup gunakan UTF-8, kecuali metode penyimpanan atau transportasi Anda antara pembuat enkode dan dekoder tidak aman untuk biner.

  • Jika tidak, gunakan urutan escape numerik.

thomasrutter
sumber
1
"semua dekoder JSON dapat menangani UTF-8" Meskipun ini berlaku untuk browser, hanya karena standar mengharuskannya tidak berarti semua perangkat lunak decoding JSON mendukung UTF-8.
Michael Mior
7
"Semua dekoder JSON dapat menangani UTF-8" benar. Jika ada sesuatu yang tidak dapat menerima UTF-8, itu bukan dekoder JSON. Ini mungkin mirip dengan dekoder JSON, tapi jelas bukan salah satunya.
thomasrutter
Saya kira itu tergantung pada definisi dekoder JSON yang Anda gunakan, tetapi poin yang adil :)
Michael Mior
Alasan RFC 8259 menetapkan dukungan UTF-8 sebagai wajib adalah karena itulah yang distandarisasi oleh dunia. Spesifikasi usang sebelumnya mendefinisikan string sebagai Unicode tetapi tidak menentukan pengkodean yang mana; implementasi standar pada UTF-8 dan spesifikasi yang diperbarui mencerminkan hal itu.
thomasrutter
Dukungan UTF-8 tidak ditentukan sebagai wajib dalam RFC itu untuk perangkat lunak tertentu sejauh yang saya tahu. Satu-satunya penyebutan UTF-8 adalah bahwa itu harus digunakan sebagai pengkodean untuk JSON yang dipertukarkan di luar sistem tertutup. Ini tidak menyiratkan bahwa semua dekoder JSON (bahasa yang tidak digunakan di RFC) harus mendukung UTF-8.
Michael Mior
17

Saya punya masalah di sana. Ketika I JSON menyandikan string dengan karakter seperti "é", setiap browser akan mengembalikan "é" yang sama, kecuali IE yang akan mengembalikan "\ u00e9".

Kemudian dengan PHP json_decode () akan gagal jika menemukan "é", jadi untuk Firefox, Opera, Safari dan Chrome, saya harus memanggil utf8_encode () sebelum json_decode ().

Catatan: dengan pengujian saya, IE dan Firefox menggunakan objek JSON asli mereka, browser lain menggunakan json2.js.

Tim Tisdall
sumber
10
Mungkin yang Anda maksud utf8_encode(), php.net/manual/en/function.utf8-encode.php
Binyamin
4
Jika IE gagal untuk memecahkan kodenya, itu adalah bug di dekoder JSON apa pun yang Anda gunakan. Semua dekoder JSON harus berhasil mendekode formulir yang dikodekan, atau mereka bukan dekoder JSON. Adapun masalah Anda dengan json_decode () dengan é unescaped, mungkin saja teks yang Anda berikan bukan UTF-8. Dekoder JSON selalu mengasumsikan UTF-8, bahkan implementasi PHP, meskipun PHP biasanya tidak mengasumsikan UTF-8 di banyak fungsi lainnya. Ada pengkodean karakter lain yang dapat menyertakan é unescaped dan terlihat identik di layar, tetapi bukan UTF-8. Pengkodean dalam bentuk \ uXXXX adalah solusi untuk ini.
thomasrutter
Hanya mengatakan: JSON secara legal dapat datang dalam pengkodean Unicode apa pun (UTF-8, UTF-16 BE / LE, UTF32 BE / LE, dengan atau tanpa penanda urutan byte). Dan karena ASCII adalah bagian dari UTF-8, ASCII juga bisa datang dalam ASCII. Misalnya apakah parser menerima UTF-32, saya tidak tahu.
gnasher729
1
Itu benar, dan pengurai tidak perlu mendukung apa pun selain UTF-8. Dari spesifikasi: "Teks JSON HARUS dienkode dalam UTF-8, UTF-16, atau UTF-32. Encoding defaultnya adalah UTF-8, dan teks JSON yang dienkode dalam UTF-8 dapat dioperasikan dalam arti bahwa keduanya akan berhasil dibaca dengan jumlah maksimum implementasi; ada banyak implementasi yang tidak berhasil membaca teks dalam pengkodean lain (seperti UTF-16 dan UTF-32). Implementasi TIDAK HARUS menambahkan tanda urutan byte ke awal teks JSON. "
thomasrutter
@thomasrutter Spesifikasi yang Anda kutip sudah lama. Spesifikasi saat ini mengatakan: " Teks JSON yang dipertukarkan antara sistem yang bukan bagian dari ekosistem tertutup HARUS dienkode menggunakan UTF-8. Spesifikasi JSON sebelumnya tidak mewajibkan penggunaan UTF-8 saat mentransmisikan teks JSON. Namun, sebagian besar implementasi perangkat lunak berbasis JSON telah memilih untuk menggunakan pengkodean UTF-8, sejauh itu adalah satu-satunya pengkodean yang mencapai interoperabilitas. Penerapan TIDAK HARUS menambahkan tanda urutan byte (U + FEFF) ke awal jaringan yang ditransmisikan Teks JSON. "
Remy Lebeau
12

ASCII tidak ada di dalamnya lagi. Menggunakan pengkodean UTF-8 berarti Anda tidak menggunakan pengkodean ASCII. Untuk apa Anda harus menggunakan mekanisme pelolosan adalah apa yang dikatakan RFC:

Semua karakter Unicode dapat ditempatkan di dalam tanda kutip kecuali untuk karakter yang harus diloloskan: tanda kutip, solidus terbalik, dan karakter kontrol (U + 0000 hingga U + 001F)

kekacauan
sumber
1
Jika membaca kutipan yang Anda berikan, Anda akan melihat bahwa Anda tidak diharuskan untuk keluar dari semua karakter unicode, hanya beberapa karakter khusus. Tetapi Anda diharuskan untuk menyandikan hasil (sebaiknya dengan utf-8). Jadi pertanyaannya adalah: "Mengapa repot-repot keluar dari karakter unicode normal jika Anda encoding utf-8".
schickb
Juga, string yang dikodekan ascii adalah subset murni dari utf-8. Jika saya menggunakan json's escaping untuk semua karakter non-ascii, hasilnya adalah ascii - dan karena itu utf-8. Berbagai perpustakaan json (seperti python simplejson) memiliki mode untuk memaksa hasil ascii. Saya berasumsi karena suatu alasan, seperti mungkin eksekusi di browser.
schickb
Ketika Anda repot-repot keluar, karakter unicode normal berada dalam konteks di mana mereka adalah karakter meta, seperti string. (Bagian RFC yang saya kutip adalah tentang string; maaf, tidak jelas tentang itu.) Anda tidak perlu melakukan keluaran ASCII sepanjang waktu; Saya pikir itu lebih untuk debugging dengan browser yang rusak.
kekacauan
7

Saya menghadapi masalah yang sama. Ini bekerja untuk saya. Tolong periksa ini.

json_encode($array,JSON_UNESCAPED_UNICODE);
Ankit Sewadik
sumber
Perlu dicatat bahwa yang di atas adalah PHP, karena pertanyaannya sama sekali tidak spesifik untuk PHP dan hanya berbicara tentang layanan web yang juga mungkin tidak menggunakan PHP (karena pembaca kami yang lama mungkin masih ingat ...)
ntninja
1

Membaca json rfc ( http://www.ietf.org/rfc/rfc4627.txt ) jelas bahwa pengkodean yang disukai adalah utf-8.

FYI, RFC 4627 bukan lagi spesifikasi JSON resmi. Itu usang pada tahun 2014 oleh RFC 7159 , yang kemudian dihilangkan pada tahun 2017 oleh RFC 8259 , yang merupakan spesifikasi saat ini.

RFC 8259 menyatakan:

8.1. Pengkodean Karakter

Teks JSON yang dipertukarkan antara sistem yang bukan bagian dari ekosistem tertutup HARUS dienkode menggunakan UTF-8 [RFC3629] .

Spesifikasi JSON sebelumnya tidak mengharuskan penggunaan UTF-8 saat mentransmisikan teks JSON. Namun, sebagian besar implementasi perangkat lunak berbasis JSON telah memilih untuk menggunakan pengkodean UTF-8, sejauh itu adalah satu-satunya pengkodean yang mencapai interoperabilitas.

Implementasi TIDAK HARUS menambahkan tanda urutan byte (U + FEFF) ke awal teks JSON yang ditransmisikan melalui jaringan. Untuk kepentingan interoperabilitas, implementasi yang mengurai teks JSON MUNGKIN mengabaikan keberadaan tanda urutan byte alih-alih memperlakukannya sebagai kesalahan.

Remy Lebeau
sumber
0

Saya memiliki masalah serupa dengan é char ... Saya pikir komentar "ada kemungkinan bahwa teks yang Anda berikan bukan UTF-8" mungkin dekat dengan tanda di sini. Saya merasa pemeriksaan default dalam contoh saya adalah sesuatu yang lain sampai saya menyadari dan berubah menjadi utf8 ... masalah adalah datanya sudah ada di sana, jadi tidak yakin apakah itu mengubah data atau tidak ketika saya mengubahnya, ditampilkan dengan baik di mysql meja kerja. Hasil akhirnya adalah bahwa php tidak akan menyandikan data, hanya mengembalikan false. Tidak peduli browser apa yang Anda gunakan sebagai server yang menyebabkan masalah saya, php tidak akan mengurai data ke utf8 jika karakter ini ada. Seperti saya katakan tidak yakin apakah itu karena mengubah skema ke utf8 setelah data ada atau hanya bug php. Dalam kasus ini digunakanjson_encode(utf8_encode($string));

Paul Smith
sumber