Nội dung kiểu gì: ứng dụng / json; charset = utf-8 có nghĩa là gì?


284

Khi tôi thực hiện một yêu cầu POST với phần thân JSON cho dịch vụ REST của mình, tôi sẽ đưa Content-type: application/json; charset=utf-8vào tiêu đề thư. Không có tiêu đề này, tôi nhận được một lỗi từ dịch vụ. Tôi cũng có thể sử dụng thành công Content-type: application/jsonmà không cần ;charset=utf-8phần.

Chính xác thì charset=utf-8làm gì? Tôi biết nó chỉ định mã hóa ký tự nhưng dịch vụ hoạt động tốt mà không có nó. Liệu mã hóa này có giới hạn các ký tự có thể có trong nội dung thư không?



8
Thật thú vị, theo Đăng ký loại phương tiện của IANAapplication/json , dường như không có một charsettham số nào được hỗ trợ , mặc dù thường được cung cấp trong thực tế.
Uux

1
I know it specifies the character encoding but the service works fine without it."Làm việc" không phải lúc nào cũng có nghĩa là "mã / cấu hình tồn tại là cách chính xác nhất bao gồm tất cả các trường hợp góc để làm một việc". Nó phụ thuộc vào tất cả các quy ước và giả định có thể không hoạt động trong các trường hợp khác. Đối với cá nhân tôi, tôi luôn cố gắng rõ ràng nhất có thể.
WesternGun

3
Gửi một tham số "bộ ký tự" là không chính xác và vô nghĩa. Xem RFC 8259, Phần 11, câu cuối cùng.
Julian Reschke

Câu trả lời:


283

Tiêu đề chỉ biểu thị nội dung được mã hóa. Không nhất thiết có thể suy ra loại nội dung từ chính nội dung đó, tức là bạn không nhất thiết chỉ cần nhìn vào nội dung và biết phải làm gì với nội dung đó. Đó là những gì các tiêu đề HTTP dành cho, chúng cho người nhận biết loại nội dung mà họ (được cho là) ​​đang xử lý.

Content-type: application/json; charset=utf-8chỉ định nội dung ở định dạng JSON, được mã hóa theo mã hóa ký tự UTF-8. Việc chỉ định mã hóa có phần dư thừa đối với JSON, vì mã hóa mặc định (chỉ?) Cho JSON là UTF-8. Vì vậy, trong trường hợp này, máy chủ nhận rõ ràng rất vui khi biết rằng nó đang xử lý JSON và giả định rằng mã hóa là UTF-8 theo mặc định, đó là lý do tại sao nó hoạt động có hoặc không có tiêu đề.

Liệu mã hóa này có giới hạn các ký tự có thể có trong nội dung thư không?

Không. Bạn có thể gửi bất cứ thứ gì bạn muốn trong tiêu đề và phần thân. Nhưng, nếu cả hai không khớp nhau, bạn có thể nhận được kết quả sai. Nếu bạn chỉ định trong tiêu đề rằng nội dung được mã hóa UTF-8 nhưng thực tế bạn đang gửi nội dung được mã hóa Latin1, người nhận có thể tạo dữ liệu rác, cố gắng diễn giải dữ liệu được mã hóa Latin1 là UTF-8. Tất nhiên, nếu bạn xác định rằng bạn đang gửi dữ liệu được mã hóa Latin1 và bạn thực sự đang làm như vậy, thì có, bạn bị giới hạn ở 256 ký tự bạn có thể mã hóa bằng Latin1.


4
Tất nhiên, trong JSON bạn vẫn có thể biểu diễn các ký tự không phải là Latin1 bằng cách sử dụng các chuỗi thoát như thế nào \u20AC.
dan04

31
Theo tiêu chuẩn cho json, bạn thực sự không được phép sử dụng latin1 để mã hóa nội dung. Nội dung JSON phải được mã hóa dưới dạng unicode, có thể là UTF-8, UTF-16 hoặc UTF-32 (endian lớn hoặc nhỏ).
Daniel Luna

20
Không có tham số bộ ký tự trên ứng dụng / json.
Julian Reschke

7
@DanielLuna là đúng, application/jsonphải là một trong những định dạng chuyển đổi ucs. Ngoài ra, vì bốn byte đầu tiên của JSON bị giới hạn, bạn luôn có thể biết liệu đó là 8, 16 hay 32 cuối cùng của nó.
Jason Coco

4
Sự kiện nếu nó là dư thừa, bạn có thể muốn đưa vào charset=utf-8vì lý do bảo mật: github.com/shieldfy/API-Security-Checklist/issues/25
manuc66

143

Để chứng minh cho tuyên bố của @ deceze rằng mã hóa JSON mặc định là UTF-8 ...

Từ IETF RFC4627 :

Văn bản JSON SALL được mã hóa bằng Unicode. Mã hóa mặc định là UTF-8.

Vì hai ký tự đầu tiên của văn bản JSON sẽ luôn là các ký tự ASCII [RFC0020], nên có thể xác định xem một luồng octet là UTF-8, UTF-16 (BE hay LE) hay UTF-32 (BE hoặc LE) bằng cách nhìn vào mô hình null trong bốn octet đầu tiên.

      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
Nó luôn giúp suy nghĩ về JSON như định dạng nhị phân, không phải định dạng văn bản.
Sulthan

2
Bây giờ RFC4627 đã bị RFC7159 lỗi thời, trong đó tuyên bố rằng giá trị gốc có thể là một chuỗi (trái ngược với thông số kỹ thuật trước đây), làm thế nào bây giờ được thực hiện? Thông số kỹ thuật là mơ hồ về vấn đề này, và chỉ nói rằng ba mã hóa được cho phép, nhưng không phải là cách người ta phải phân biệt chúng.
Fabio Beltramini

4
@FabioBeltramini Ở trên vẫn nên giữ, bởi vì một chuỗi trong JSON sẽ không chứa bất kỳ ký tự null nào (null trong JSON sẽ cần được mã hóa bằng một chuỗi thoát số tức là "\u0000").
thomasrutter

3
Trên thực tế, ký tự thứ hai trong UTF-16xx có thể không có NULL trong trường hợp đó, nhưng vẫn có thể xác định mã hóa từ các byte khác: xx 00 00 00vẫn là UTF-32LE và xx 00 xx xxvẫn là UTF-16LE, 00 xx xx xxvẫn là UTF-16BE.
thomasrutter

20

Lưu ý rằng IETF RFC4627 đã được thay thế bởi IETF RFC7158 . Trong phần [8.1], nó rút lại văn bản được trích dẫn bởi @Drew trước đó bằng cách nói:

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

Giả định vẫn còn mặc dù, vì bất kỳ json hợp lệ nào vẫn sẽ bắt đầu với hai ký tự ascii.
Larsing

Một ký tự, bởi vì một chữ số duy nhất là một tệp JSON hợp lệ
Nayuki

0

Tôi hoàn toàn đồng ý với @deceze nhưng tôi muốn phát triển phần "Tôi gặp lỗi từ dịch vụ" của câu hỏi này,

Chúng tôi nhận được loại lỗi này là http 415

Lỗi loại không được hỗ trợ

Mã phản hồi lỗi máy khách Loại không hỗ trợ HTTP 415 cho biết rằng máy chủ từ chối chấp nhận yêu cầu vì định dạng tải trọng ở định dạng không được hỗ trợ.

Sự cố định dạng có thể là do Loại nội dung hoặc Mã hóa nội dung được chỉ định của yêu cầu hoặc do kiểm tra trực tiếp dữ liệu.

Nói cách khác, như đã thấy trong https://stackoverflow.com/a/22643964/914284 ví dụ này.

  • Chúng tôi phải đặt loại nội dung chính xác và chúng tôi phải chấp nhận loại nội dung phù hợp như đã thấy Thêm Loại nội dung: application / json và Accept: application / json. Nếu không, nó sẽ mặc định

0

Quá trình triển khai của Dart http xử lý các byte nhờ vào "charset = utf-8", vì vậy tôi chắc chắn một số triển khai ngoài đó hỗ trợ điều này, để tránh bộ ký tự dự phòng "latin-1" khi đọc các byte từ phản hồi. Trong trường hợp của tôi, tôi hoàn toàn mất định dạng trên chuỗi thân phản hồi, vì vậy tôi phải thực hiện mã hóa byte theo cách thủ công thành utf8 hoặc thêm tham số "bên trong" tiêu đề đó vào phản hồi API của máy chủ.


0

Tôi đã sử dụng HttpClient và nhận lại tiêu đề phản hồi với loại nội dung application/json, tôi bị mất các ký tự như tiếng nước ngoài hoặc ký hiệu sử dụng unicode vì HttpClient được mặc định là ISO-8859-1 . Vì vậy, hãy rõ ràng nhất có thể như được đề cập bởi @WesternGun để tránh mọi vấn đề có thể xảy ra.

Không có cách nào xử lý do máy chủ không xử lý bộ ký tự tiêu đề được yêu cầu ( method.setRequestHeader("accept-charset", "UTF-8");) cho tôi và tôi đã phải truy xuất dữ liệu phản hồi dưới dạng vẽ byte và chuyển đổi nó thành Chuỗi bằng UTF-8. Vì vậy, nên rõ ràng và tránh giả định giá trị mặc định.

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.