Co oznacza „Typ zawartości: aplikacja / json; charset = utf-8 ”naprawdę znaczy?


284

Kiedy wysyłam żądanie POST z treścią JSON do mojej usługi REST, dołączam Content-type: application/json; charset=utf-8do nagłówka komunikatu. Bez tego nagłówka otrzymuję błąd z usługi. Mogę również z powodzeniem korzystać Content-type: application/jsonbez ;charset=utf-8porcji.

Co dokładnie robi charset=utf-8? Wiem, że określa kodowanie znaków, ale usługa działa bez niego. Czy to kodowanie ogranicza znaki, które mogą znajdować się w treści wiadomości?



8
Co ciekawe, zgodnie z rejestracją typu mediów IANAapplication/json , wydaje się, że nie ma charsetw ogóle obsługiwanego parametru, choć często jest on dostarczany w praktyce.
Uux,

1
I know it specifies the character encoding but the service works fine without it.„działający” nie zawsze oznacza „istniejący kod / konfiguracja jest najbardziej poprawnym sposobem obejmującym wszystkie narożne przypadki, aby wykonać jedną rzecz”. Zależy to od wszystkich konwencji i założeń, które mogą nie działać w innych okolicznościach. Dla mnie osobiście zawsze staram się być tak wyraźny, jak to możliwe.
WesternGun

3
Wysłanie parametru „charset” jest niepoprawne i bez znaczenia. Patrz RFC 8259, sekcja 11, ostatnie zdanie.
Julian Reschke

Odpowiedzi:


283

Nagłówek oznacza po prostu, w co jest zakodowana treść. Niekoniecznie jest możliwe wywnioskowanie rodzaju treści z samej treści, tzn. Nie można po prostu spojrzeć na treść i wiedzieć, co z nią zrobić. Właśnie po to są nagłówki HTTP, mówią odbiorcy, z jakim rodzajem treści (podobno) mają do czynienia.

Content-type: application/json; charset=utf-8oznacza treść w formacie JSON, zakodowaną w kodowaniu znaków UTF-8. Oznaczenie kodowania jest nieco zbędne dla JSON, ponieważ domyślnym (tylko?) Kodowaniem dla JSON jest UTF-8. Więc w tym przypadku serwer odbierający najwyraźniej jest szczęśliwy wiedząc, że ma do czynienia z JSON i zakłada, że ​​kodowanie jest domyślnie UTF-8, dlatego działa z nagłówkiem lub bez.

Czy to kodowanie ogranicza znaki, które mogą znajdować się w treści wiadomości?

Nie. Możesz wysłać cokolwiek chcesz w nagłówku i treści. Ale jeśli nie pasują do siebie, możesz uzyskać błędne wyniki. Jeśli określisz w nagłówku, że treść jest zakodowana w UTF-8, ale faktycznie wysyłasz zawartość zakodowaną w Latin1, odbiornik może generować niepotrzebne dane, próbując interpretować dane zakodowane w Latin1 jako UTF-8. Jeśli oczywiście określisz, że wysyłasz dane zakodowane w Latin1 i faktycznie to robisz, to tak, jesteś ograniczony do 256 znaków, które możesz zakodować w Latin1.


4
Oczywiście w JSON nadal możesz reprezentować znaki spoza alfabetu łacińskiego 1, używając sekwencji specjalnych, takich jak \u20AC.
dan04,

31
Zgodnie ze standardem dla json, tak naprawdę nie wolno używać latin1 do kodowania zawartości. Treść JSON musi być zakodowana jako Unicode, czy to UTF-8, UTF-16, czy UTF-32 (duży czy mały endian).
Daniel Luna

20
Nie ma parametru charset w aplikacji / json.
Julian Reschke,

7
@DanielLuna ma rację, application/jsonmusi być w jednym z formatów transformacji ucs. Ponadto, ponieważ pierwsze cztery bajty JSON są ograniczone, zawsze możesz stwierdzić, czy jest to 8, 16 lub 32 i jego endianność.
Jason Coco

4
Zdarzenie, jeśli jest zbędne, które możesz chcieć uwzględnić charset=utf-8ze względów bezpieczeństwa: github.com/shieldfy/API-Security-Checklist/issues/25
manuc66

143

Aby uzasadnić twierdzenie @ deceze, że domyślnym kodowaniem JSON jest UTF-8 ...

Z IETF RFC4627 :

Tekst JSON MUSI być zakodowany w standardzie Unicode. Domyślne kodowanie to UTF-8.

Ponieważ pierwsze dwa znaki tekstu JSON będą zawsze znakami ASCII [RFC0020], można ustalić, czy strumień oktetów to UTF-8, UTF-16 (BE lub LE), czy UTF-32 (BE lub LE) patrząc na wzór zer w pierwszych czterech oktetach.

      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
Zawsze pomaga myśleć o JSON jako formacie binarnym, a nie tekstowym.
Sulthan,

2
Teraz, gdy RFC4627 został zdezaktualizowany przez RFC7159, który stwierdza, że ​​wartość root może być łańcuchem (w wyraźnym kontraście do poprzedniej specyfikacji), jak to teraz jest realizowane? Specyfikacja jest pod tym względem niejasna i mówi tylko, że dozwolone są trzy kodowania, ale nie w jaki sposób należy je rozróżnić.
Fabio Beltramini

4
@FabioBeltramini Powyższe powinno nadal obowiązywać, ponieważ ciąg znaków w JSON nie będzie zawierał żadnych literalnych znaków zerowych (wartości Null w JSON musiałyby być zakodowane za pomocą numerycznej sekwencji ucieczki, tj "\u0000".).
thomasrutter

3
Właściwie drugi znak w UTF-16xx może w tym przypadku nie mieć wartości NULL, ale nadal będzie można określić kodowanie na podstawie innych bajtów: xx 00 00 00nadal jest UTF-32LE i xx 00 xx xxwciąż jest UTF-16LE, 00 xx xx xxwciąż jest UTF-16BE.
thomasrutter

20

Należy pamiętać, że IETF RFC4627 został zastąpiony przez IETF RFC7158 . W sekcji [8.1] cofa tekst cytowany wcześniej przez @Drew, mówiąc:

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

Założenie to nadal obowiązuje, ponieważ każdy prawidłowy Json nadal będzie zaczynać się od dwóch znaków ascii.
Larsing,

Jeden znak, ponieważ pojedyncza cyfra jest prawidłowym plikiem JSON
Nayuki,

0

Dokładnie zgadzam się z @deceze, ale chcę rozwinąć tę część pytania „otrzymuję błąd z usługi” ,

Otrzymujemy tego rodzaju błędy jako http 415

Http 415 Błąd nieobsługiwanego typu nośnika

Kod odpowiedzi klienta na błąd nieobsługiwanego typu HTTP 415 wskazuje, że serwer odmawia przyjęcia żądania, ponieważ format ładunku jest nieobsługiwany.

Problem z formatem może być spowodowany wskazanym typem treści lub kodowaniem treści lub bezpośrednim sprawdzeniem danych.

Innymi słowy, na przykład w https://stackoverflow.com/a/22643964/914284 w tym przykładzie.

  • Musimy ustawić poprawny typ zawartości i musimy zaakceptować odpowiedni typ treści, jak widać. Dodaj typ zawartości: application / json i Accept: application / json. W przeciwnym razie przyjmie wartość domyślną

0

Implementacja Dart http przetwarza bajty dzięki temu „charset = utf-8”, więc jestem pewien, że kilka implementacji tam to obsługuje, aby uniknąć rezerwowego zestawu znaków „latin-1” podczas odczytu bajtów z odpowiedzi. W moim przypadku całkowicie tracę format ciągu znaków odpowiedzi, więc muszę ręcznie kodować bajty do utf8 lub dodać ten parametr „wewnętrzny” nagłówka w odpowiedzi interfejsu API mojego serwera.


0

Używałem HttpClient i otrzymywałem nagłówek odpowiedzi z typem treści application/json, straciłem znaki, takie jak języki obce lub symbol, który używał Unicode, ponieważ HttpClient jest domyślnie ustawiony na ISO-8859-1 . Tak więc, bądź wyraźny, jak to możliwe, jak wspomniano w @WesternGun, aby uniknąć ewentualnego problemu.

Nie ma mowy o tym, że serwer nie obsługuje charset ( method.setRequestHeader("accept-charset", "UTF-8");) żądanego nagłówka i musiałem pobrać dane odpowiedzi jako bajty rysujące i przekonwertować je na String za pomocą UTF-8. Dlatego zaleca się, aby być jawnym i unikać zakładania wartości domyślnej.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.