Mã hóa ký tự JSON - UTF-8 có được hỗ trợ tốt bởi các trình duyệt hay tôi nên sử dụng chuỗi thoát số?


89

Tôi đang viết một dịch vụ web sử dụng json để đại diện cho các tài nguyên của nó và tôi hơi khó nghĩ về cách tốt nhất để mã hóa json. Đọc json rfc ( http://www.ietf.org/rfc/rfc4627.txt ) rõ ràng là kiểu mã hóa ưu tiên là utf-8. Nhưng rfc cũng mô tả một cơ chế thoát chuỗi để chỉ định các ký tự. Tôi cho rằng điều này thường được sử dụng để thoát các ký tự không phải ascii, do đó làm cho kết quả utf-8 ascii hợp lệ.

Vì vậy, giả sử tôi có một chuỗi json chứa các ký tự unicode (điểm mã) không phải là ascii. Dịch vụ web của tôi nên mã hóa utf-8 và trả lại nó, hay nó phải thoát tất cả các ký tự không phải ascii đó và trả về ascii thuần túy?

Tôi muốn các trình duyệt có thể thực thi kết quả bằng jsonp hoặc eval. Điều đó có ảnh hưởng đến quyết định? Kiến thức của tôi về hỗ trợ javascript của các trình duyệt khác nhau cho utf-8 còn thiếu.

CHỈNH SỬA: Tôi muốn làm rõ rằng mối quan tâm chính của tôi về cách mã hóa kết quả thực sự là về việc xử lý kết quả của trình duyệt. Những gì tôi đã đọc chỉ ra rằng các trình duyệt có thể nhạy cảm với mã hóa khi sử dụng JSONP nói riêng. Tôi không tìm thấy bất kỳ thông tin thực sự tốt nào về chủ đề này, vì vậy tôi sẽ phải bắt đầu thực hiện một số thử nghiệm để xem điều gì sẽ xảy ra. Lý tưởng nhất là tôi chỉ muốn thoát một số ký tự được yêu cầu và chỉ mã hóa utf-8 kết quả.

Câu trả lời:


88

Đặc tả JSON yêu cầu bộ giải mã hỗ trợ UTF-8. Do đó, tất cả các bộ giải mã JSON đều có thể xử lý UTF-8 cũng như chúng có thể xử lý các chuỗi thoát số. Đây cũng là trường hợp của trình thông dịch Javascript, có nghĩa là JSONP cũng sẽ xử lý JSON được mã hóa UTF-8.

Khả năng bộ mã hóa JSON sử dụng các chuỗi thoát số thay vào đó chỉ cung cấp cho bạn nhiều lựa chọn hơn. Một lý do khiến bạn có thể chọn trình tự thoát dạng số là nếu cơ chế truyền tải giữa bộ mã hóa của bạn và bộ giải mã dự kiến ​​không an toàn nhị phân.

Một lý do khác mà bạn có thể muốn sử dụng trình tự thoát số là để ngăn chặn một số nhân vật xuất hiện trong dòng, chẳng hạn như <, &", trong đó có thể được giải thích dưới dạng HTML chuỗi nếu mã JSON được đặt mà không cần thoát sang HTML hoặc một trình duyệt không đúng diễn giải nó dưới dạng HTML . Đây có thể là một biện pháp bảo vệ chống lại việc chèn HTML hoặc tập lệnh giữa các trang web (lưu ý: một số ký tự PHẢI được thoát trong JSON, bao gồm "\).

Một số khung công tác, bao gồm cả việc triển khai JSON của PHP, luôn thực hiện các chuỗi thoát dạng số ở phía bộ mã hóa cho bất kỳ ký tự nào bên ngoài ASCII. Điều này nhằm mục đích tương thích tối đa với các cơ chế vận chuyển hạn chế và những thứ tương tự. Tuy nhiên, điều này không nên được hiểu là một dấu hiệu cho thấy bộ giải mã JSON có vấn đề với UTF-8.

Vì vậy, tôi đoán bạn chỉ có thể quyết định sử dụng như thế này:

  • Chỉ cần sử dụng UTF-8, trừ khi phương pháp lưu trữ hoặc vận chuyển của bạn giữa bộ mã hóa và bộ giải mã không an toàn nhị phân.

  • Nếu không, hãy sử dụng các chuỗi thoát số.


1
"tất cả các bộ giải mã JSON đều có thể xử lý UTF-8" Mặc dù điều này đúng với các trình duyệt, chỉ vì tiêu chuẩn yêu cầu nên không có nghĩa là tất cả các phần mềm giải mã JSON đều hỗ trợ UTF-8.
Michael Mior

7
"Tất cả các bộ giải mã JSON có thể xử lý UTF-8" đúng theo nghĩa đen. Nếu thứ gì đó không thể chấp nhận UTF-8 thì đó không phải là bộ giải mã JSON. Nó có thể tương tự như bộ giải mã JSON, nhưng nó chắc chắn không phải là một.
thomasrutter

Tôi đoán điều đó phụ thuộc vào định nghĩa của bộ giải mã JSON mà bạn đang sử dụng, nhưng điểm công bằng :)
Michael Mior

Lý do RFC 8259 chỉ định hỗ trợ UTF-8 là bắt buộc vì đó là thứ mà thế giới đã tiêu chuẩn hóa. Các thông số kỹ thuật lỗi thời trước đây đã xác định các chuỗi là Unicode nhưng không chỉ định mã hóa nào; các triển khai được chuẩn hóa trên UTF-8 và thông số kỹ thuật được cập nhật phản ánh điều đó.
thomasrutter

Hỗ trợ UTF-8 không được chỉ định là bắt buộc trong RFC đó đối với bất kỳ phần mềm cụ thể nào theo như tôi có thể nói. Đề cập duy nhất của UTF-8 là nó phải được sử dụng làm mã hóa cho JSON được trao đổi bên ngoài một hệ thống đóng. Điều này không có nghĩa là tất cả các bộ giải mã JSON (một ngôn ngữ không được sử dụng trong RFC) phải hỗ trợ UTF-8.
Michael Mior

17

Tôi đã có một vấn đề ở đó. Khi tôi JSON mã hóa một chuỗi có ký tự như "é", mọi trình duyệt sẽ trả về cùng một "é", ngoại trừ IE sẽ trả về "\ u00e9".

Sau đó với PHP json_decode (), nó sẽ không thành công nếu tìm thấy "é", vì vậy đối với Firefox, Opera, Safari và Chrome, tôi phải gọi utf8_encode () trước json_decode ().

Lưu ý: với các thử nghiệm của tôi, IE và Firefox đang sử dụng đối tượng JSON gốc của chúng, các trình duyệt khác đang sử dụng json2.js.


10
Có lẽ bạn có nghĩa là utf8_encode(), php.net/manual/en/function.utf8-encode.php
Binyamin

4
Nếu IE không giải mã được điều đó, đó là lỗi trong bất kỳ bộ giải mã JSON nào bạn đang sử dụng. Tất cả bộ giải mã JSON phải giải mã thành công biểu mẫu được mã hóa hoặc chúng không phải là bộ giải mã JSON. Đối với vấn đề của bạn với json_decode () với chữ é không thoát, có thể văn bản bạn đang cung cấp cho nó không phải là UTF-8. Bộ giải mã JSON luôn giả sử UTF-8, ngay cả việc triển khai PHP, mặc dù PHP thường không giả định UTF-8 trong nhiều hàm khác. Có những mã hóa ký tự khác có thể bao gồm một ký tự không được thoát và trông giống hệt nhau trên màn hình, nhưng không phải là UTF-8. Mã hóa trong biểu mẫu \ uXXXX là một giải pháp thay thế cho điều này.
thomasrutter

Chỉ cần nói rằng: JSON có thể hợp pháp ở bất kỳ mã hóa Unicode nào (UTF-8, UTF-16 BE / LE, UTF32 BE / LE, có hoặc không có dấu thứ tự byte). Và vì ASCII là một tập hợp con của UTF-8, nó cũng có thể có trong ASCII. Tôi không biết liệu trình phân tích cú pháp có chấp nhận UTF-32 hay không.
gnasher729

1
Điều đó đúng và trình phân tích cú pháp không bắt buộc phải hỗ trợ bất kỳ thứ gì khác ngoài UTF-8. Từ thông số kỹ thuật: "Văn bản JSON SẼ được mã hóa bằng UTF-8, UTF-16 hoặc UTF-32. Mã hóa mặc định là UTF-8 và các văn bản JSON được mã hóa bằng UTF-8 có thể tương tác theo nghĩa mà chúng sẽ được đọc thành công bởi số lượng triển khai tối đa; có nhiều triển khai không thể đọc thành công văn bản trong các mã hóa khác (chẳng hạn như UTF-16 và UTF-32). Việc triển khai KHÔNG ĐƯỢC thêm dấu thứ tự byte vào đầu văn bản JSON. "
thomasrutter

@thomasrutter Thông số bạn trích dẫn đã cũ. Thông số hiện tại cho biết: " Văn bản JSON được trao đổi giữa các hệ thống không thuộc hệ sinh thái khép kín PHẢI được mã hóa bằng UTF-8. Các thông số kỹ thuật trước đây của JSON không yêu cầu sử dụng UTF-8 khi truyền văn bản JSON. Tuy nhiên, phần lớn triển khai phần mềm dựa trên JSON đã chọn sử dụng mã hóa UTF-8, ở mức độ mà nó là mã hóa duy nhất đạt được khả năng tương tác. Việc triển khai KHÔNG PHẢI thêm dấu thứ tự byte (U + FEFF) vào đầu truyền qua mạng Văn bản JSON. "
Remy Lebeau

12

ASCII không còn trong đó nữa. Sử dụng mã hóa UTF-8 có nghĩa là bạn không sử dụng mã hóa ASCII. Những gì bạn nên sử dụng cơ chế thoát là những gì RFC nói:

Tất cả các ký tự Unicode có thể được đặt trong dấu ngoặc kép ngoại trừ các ký tự phải được thoát ra ngoài: dấu ngoặc kép, dấu gạch ngang ngược và các ký tự điều khiển (U + 0000 đến U + 001F)


1
Nếu đọc đoạn trích dẫn mà bạn cung cấp, bạn sẽ thấy rằng bạn không bắt buộc phải thoát tất cả các ký tự unicode, chỉ một số ký tự đặc biệt. Nhưng bạn được yêu cầu mã hóa kết quả (tốt nhất là với utf-8). Vì vậy, câu hỏi đặt ra là: "Tại sao phải thoát các ký tự unicode bình thường nếu bạn đang mã hóa utf-8".
schickb

Ngoài ra, một chuỗi được mã hóa ascii là một tập con thuần túy của utf-8. Nếu tôi sử dụng lối thoát của json cho tất cả các ký tự không phải ascii, kết quả là ascii - và do đó utf-8. Các thư viện json khác nhau (như python simplejson) có các chế độ để buộc kết quả ascii. Tôi đoán vì một lý do, như có lẽ là thực thi trong các trình duyệt.
schickb

Khi bạn bận tâm thoát các ký tự unicode thông thường là trong bối cảnh mà chúng là ký tự siêu, như chuỗi. (Đoạn RFC mà tôi đã trích dẫn là về chuỗi; xin lỗi, không rõ ràng về điều đó.) Bạn không cần phải thực hiện đầu ra ASCII mọi lúc; Tôi nghĩ rằng đó là nhiều hơn để gỡ lỗi với các trình duyệt bị hỏng.
hỗn loạn

7

Tôi đã phải đối mặt với cùng một vấn đề. Nó làm việc cho tôi. Làm ơn kiểm tra cái này.

json_encode($array,JSON_UNESCAPED_UNICODE);

Cần lưu ý rằng phần trên là PHP, vì câu hỏi không phải là PHP cụ thể và chỉ nói về dịch vụ web cũng có thể không sử dụng PHP (vì những dịch vụ cũ hơn mà độc giả của chúng tôi có thể vẫn nhớ…)
ntninja

1

Đọc json rfc ( http://www.ietf.org/rfc/rfc4627.txt ) rõ ràng là kiểu mã hóa ưu tiên là utf-8.

FYI, RFC 4627 không còn là thông số JSON chính thức. Nó đã được xóa sổ vào năm 2014 bởi RFC 7159 , sau đó được xóa sổ vào năm 2017 bởi RFC 8259 , đây là thông số kỹ thuật hiện tại.

RFC 8259 trạng thái:

8.1. Mã hóa ký tự

Văn bản JSON được trao đổi giữa các hệ thống không thuộc hệ sinh thái khép kín PHẢI được mã hóa bằng UTF-8 [RFC3629] .

Các thông số kỹ thuật trước đây của JSON không yêu cầu sử dụng UTF-8 khi truyền văn bản JSON. Tuy nhiên, phần lớn các triển khai phần mềm dựa trên JSON đã chọn sử dụng mã hóa UTF-8, ở mức độ mà nó là mã hóa duy nhất đạt được khả năng tương tác.

Việc triển khai KHÔNG ĐƯỢC thêm dấu thứ tự byte (U + FEFF) vào đầu văn bản JSON được truyền qua mạng. Vì lợi ích của khả năng tương tác, các triển khai phân tích cú pháp văn bản JSON CÓ THỂ bỏ qua sự hiện diện của dấu thứ tự byte thay vì coi nó như một lỗi.


0

Tôi đã gặp sự cố tương tự với é char ... Tôi nghĩ nhận xét "có thể văn bản bạn đang cho nó không phải là UTF-8" có lẽ gần với dấu ở đây. Tôi có cảm giác đối chiếu mặc định trong trường hợp của tôi là một cái gì đó khác cho đến khi tôi nhận ra và thay đổi thành utf8 ... vấn đề là dữ liệu đã ở đó, vì vậy không chắc liệu nó có chuyển đổi dữ liệu hay không khi tôi thay đổi nó, hiển thị tốt trong mysql bàn làm việc. Kết quả cuối cùng là php sẽ không mã hóa dữ liệu json, chỉ trả về false. Không quan trọng bạn sử dụng trình duyệt nào làm máy chủ gây ra sự cố của tôi, php sẽ không phân tích cú pháp dữ liệu thành utf8 nếu có ký tự này. Giống như tôi nói không chắc liệu đó có phải là do chuyển đổi lược đồ thành utf8 sau khi có dữ liệu hay chỉ là một lỗi php. Trong trường hợp này sử dụngjson_encode(utf8_encode($string));

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.