JSON Toolkit

Jak naprawić błędy parsowania JSON: krok po kroku z komunikatem Unexpected token

Podsumowanie: Zamień błędy JSON.parse na wiersz i znak, a następnie wyklucz sześć przyczyn: przecinki końcowe, pojedyncze cudzysłowy, komentarze, znaki sterujące, BOM i obcięcie.

Początkujący~12 min czytaniaOpublikowano 2026-10-30Zaktualizowano 2026-11-01
Okładka artykułu o diagnozowaniu błędów parsowania JSON

Najważniejsze: przy błędzie parsowania odczytaj zgłoszony wiersz i kolumnę, aby znaleźć pierwszy nielegalny znak, a następnie rozstrzygnij, czy brakuje cudzysłowu, brakuje przecinka, występuje przecinek końcowy, BOM lub obcięcie — nie czytaj całego dokumentu od nowa.

Komunikat błędu nigdy nie mówi „co jest nie tak”; mówi tylko „w którym miejscu parser nie mógł już kontynuować”. Te dwa położenia często nie są tym samym miejscem.

1. Najpierw przetłumacz błąd na współrzędne

Ten sam zepsuty JSON daje zupełnie różne błędy w różnych językach, ale wszystkie można przeskalować na „który wiersz, który znak”:

Środowisko Typowy błąd Jak go czytać
Przeglądarka / Node Unexpected token } in JSON at position 42 position to przesunięcie znaku liczone od 0, a nie numer wiersza
Node 20+ Unexpected non-whitespace character after JSON at position 42 oznacza, że pierwsza część jest poprawna, a nadmiarowa treść zaczyna się po 42
Java Jackson Unexpected character ('}' (code 125)): was expecting ... at [Source: (String)..."..." ; line: 3, column: 1] podaje wiersz i kolumnę bezpośrednio, najbardziej użyteczny z wszystkich
Python json.decoder.JSONDecodeError: Expecting ',' delimiter: line 3 column 1 (char 42) char to przesunięcie; liczą się wiersz i kolumna
Go invalid character '}' looking for beginning of object key string podaje tylko znak, więc trzeba samemu cofnąć się i go zlokalizować

Gdy masz już położenie, wklej JSON do parsera JSON online; narzędzie umieszcza kursor w miejscu błędu i podświetla numer wiersza i kolumny — ten krok oszczędza 90% wpatrywania się w znaki.

2. Sześć najczęstszych błędów

1. Przecinek końcowy

{
  "name": "json",
  "version": 1,
}

Przed } znajduje się zbędny przecinek. Specyfikacja JSON nie pozwala na przecinki końcowe, a literały obiektów JavaScript je dopuszczają, więc konfiguracja skopiowana z kodu najprawdopodobniej je przeniesie. Poprawka: usuń ostatni przecinek; jeśli te dane i tak należą do pliku JS, przejdź do konwersji JSON5, zamiast wciskać je w JSON.

2. Pojedyncze cudzysłowy i klucze bez cudzysłowów

{ 'name': 'json' }
{ name: "json" }

Łańcuchy JSON mogą używać wyłącznie podwójnych cudzysłowów, a klucze również muszą być łańcuchami w cudzysłowach. To dwie uproszczone konstrukcje składni JSON5 / JavaScript, a nie JSON. Cudzysłów wewnątrz łańcucha trzeba zapisać jako \", a backslash jako \\.

3. Komentarze

{
  // Timeout in milliseconds
  "timeout": 3000
}

Gramatyka RFC 8259 nie przewiduje komentarzy. Albo usuń komentarze, albo zapisz jako .jsonc / .json5 i użyj parsera obsługującego komentarze. Kompromisy między różnymi „schematami komentarzy” opisano w Jak pisać komentarze w JSON.

4. Surowe znaki nowej linii i znaki sterujące w łańcuchach

{"sql": "SELECT *
FROM t"}

Łańcuchy JSON nie mogą zawierać surowych przesunięć wiersza, tabulatorów ani znaków sterujących U+0000–U+001F; trzeba je zapisać jako \n, \t, \u0009. Wciskając wieloliniowy tekst do JSON, najpierw raz escape'uj go w edytorze albo obsłuż go jednolicie przez minifikację i ucieczkę JSON.

5. Nagłówek BOM

UTF-8 zapisany przez Notatnik w Windows niesie trzy bajty EF BB BF. JSON.parse zgłasza Unexpected token, gdy napotka BOM, a oko w ogóle go nie widzi. Jak to rozpoznać: sprawdź nagłówek pliku w systemie szesnastkowym albo skopiuj treść do narzędzia online i zobacz, czy pierwszy znak wyświetla się jako . Poprawka: zapisz jako „UTF-8 bez BOM”.

6. Obcięta treść

Log, który wypisał tylko pierwsze 4096 znaków, odpowiedź API ucięta przez bramkę, przerwane pobieranie — znakiem rozpoznawczym tej klasy jest „błąd jest na końcu” i niezgodna liczba nawiasów. Najpierw policz nawiasy: jeśli zamknięcia { i [ się nie zgadzają, to obcięcie, a nie błąd składni. W takim przypadku nic nie poprawiaj — idź po pełne dane.

3. Dwa fałszywe alarmy dotyczące chińskiego tekstu i ucieczki

Chiński zamienia się w \u4e2d\u6587: to poprawna ucieczka JSON, a nie krzaczki. Po parsowaniu wartość wraca do chińskiego; postać \u pojawia się tylko przy bezpośrednim patrzeniu na surowy łańcuch. Gdy trzeba pokazać to ludziom, po prostu wypisz przez narzędzie formatujące; o strategii ucieczki trzeba myśleć tylko wtedy, gdy chiński musi przetrwać w URL albo w logu.

Chiński zamienia się w krzaczki typu 涓枃: to problem kodowania, a nie problem JSON. Dzieje się tak, gdy bajty UTF-8 zostaną zdekodowane jako GBK, co daje ten regularny wzór „trzech znaków zamiast jednego chińskiego”. Sprawdź Content-Type: application/json; charset=utf-8 w nagłówku odpowiedzi i sprawdź, czy podczas odczytu pliku jawnie podano encoding='utf-8'.

4. Pięciominutowy proces naprawy

  1. Wklej do narzędzia: najpierw użyj parsera online, aby zlokalizować pierwszy błąd, i popraw tylko jedną rzecz naraz;
  2. Waliduj po każdej poprawce: parsuj ponownie po każdej zmianie, aby naprawianie kilku miejsc naraz nie pozwoliło nowym błędom zasłonić starego;
  3. Raz zminifikuj: usuń białe znaki przez Minify i parsuj ponownie; to rozdziela „błędy strukturalne” od „problemów z białymi znakami lub nowymi liniami”;
  4. Porównaj strukturę: jeśli błąd pojawił się nagle po zmianie, użyj JSON diff względem poprzedniej wersji; różnicą jest zwykle jeden przecinek;
  5. Walidacja na poziomie pól: jeśli składnia przechodzi, ale warstwa biznesowa odrzuca dane (brakujące pole, zły typ), to należy do walidacji JSON Schema, a nie problem składni.

5. Dlaczego jeden z dwóch „identycznie wyglądających” fragmentów JSON się parsuje, a drugi nie

Najczęstszą przyczyną są niewidoczne znaki: pełnoekranowy przecinek ,, pełnoekranowe cudzysłowy “”, niełamliwa spacja U+00A0, spacja zerowej szerokości U+200B. Na ekranie są niemal nieodróżnialne od odpowiedników półpełnoekranowych, ale żaden z nich nie należy do gramatyki JSON.

Jest tylko jeden sposób, aby to rozpoznać: skopiuj treść wokół podejrzanego znaku i sprawdź punkty kodowe bajt po bajcie. Uruchomienie poniższego w konsoli przeglądarki wypisze każdy znak, który nie jest ASCII i znajduje się poza zakresami chińskimi:

[...text].filter((ch) => {
  const code = ch.codePointAt(0);
  return code > 127 && !(code >= 0x4e00 && code <= 0x9fff);
});

Jeśli w wyniku pojawi się 0x201c (lewy cudzysłów), 0xff0c (pełnoekranowy przecinek) lub 0x00a0, to one są winowajcami.

6. Zapobieganie jest tańsze niż naprawa

  • Uruchamiaj sprawdzenie parsowania plików konfiguracyjnych przed commitem; jedna linia w CI wystarczy: node -e "JSON.parse(require('fs').readFileSync('config.json','utf8'))";
  • Generuj odpowiedzi API biblioteką serializującą; nigdy nie sklejaj łańcuchów ręcznie — ręcznie budowane łańcuchy są jedynym źródłem przecinków końcowych i brakujących cudzysłowów;
  • Logując JSON, najpierw wywołaj JSON.stringify, zamiast interpolować go do szablonu, aby na wpół zapisany ładunek nie został wzięty za kompletną wiadomość.

FAQ

Jak szybko zlokalizować położenie błędu składni JSON?

Weź position lub wiersz i kolumnę zgłoszone przez parser; position to przesunięcie znaku liczone od 0, a nie numer wiersza, podczas gdy Java Jackson i Python podają wiersz i kolumnę bezpośrednio. Wklej JSON do parsera JSON online, a narzędzie umieści kursor w miejscu błędu i podświetli wiersz i kolumnę. Jeśli błąd jest na początku, sprawdź nagłówek pliku pod kątem BOM i poszukaj niewidocznych znaków.

Dlaczego konfiguracja skopiowana z kodu tak łatwo przenosi przecinek końcowy?

Specyfikacja JSON zabrania przecinków końcowych, a literały obiektów JavaScript je dopuszczają, więc konfiguracja skopiowana z kodu JS łatwo bierze jeden ze sobą. Poprawka polega po prostu na usunięciu ostatniego przecinka; jeśli dane i tak należą do pliku JS, przejście do konwersji JSON5 pasuje lepiej niż wciskanie ich w JSON.

Czy plik konfiguracyjny zawierający komentarze można sparsować jako zwykły JSON?

Nie — gramatyka RFC 8259 nie przewiduje komentarzy, więc bezpośrednie parsowanie zgłasza błąd. Albo usuń komentarze, albo zapisz jako .jsonc / .json5 i użyj parsera obsługującego komentarze. Kompromisy między schematami komentarzy opisano w Jak pisać komentarze w JSON.