Formularz zostaje wysłany, pojawia się wskaźnik, a konsola mówi o nieoczekiwanym znaku < w JSON na pozycji 0. Sama strona ładuje się dobrze, dlatego pierwszym odruchem jest obwinianie parsera albo tunelu. Zwykle żaden z nich nie bierze w tym udziału: wysłanie to inne żądanie niż wczytanie strony, a wróciło coś, co nie jest JSON-em. Pracuj w kolejności, w jakiej przeglądarka naprawdę to ujawnia, bo cztery możliwe odpowiedzi wymagają czterech różnych napraw.

Krok 1: przechwyć wysłanie, które naprawdę nastąpiło

Otwórz panel Sieć przed wysłaniem, ustaw dziennik tak, aby zachowywał wpisy między nawigacjami, a następnie wykonaj jedno nieszkodliwe wysłanie testowe na koncie, którego wolno ci użyć. Wybierz żądanie rozpoczęte przez sam formularz, a nie żądanie dokumentu strony.

Uważaj na filtry. Filtr XHR lub Fetch jest wygodny, ale jeśli framework nadal wysyła przez ukryty iframe albo dynamicznie utworzony formularz, filtr ukryje jedyne ważne żądanie. Wyślij najpierw raz bez filtra i zobacz, co się pojawiło.

Dla wybranego żądania zanotuj sześć rzeczy przed jakąkolwiek interpretacją: metodę, pełny URL wraz z ciągiem zapytania, status, łańcuch przekierowań, Content-Type odpowiedzi oraz pierwsze linie treści. Dokumentacja panelu Sieć w Chrome DevTools opisuje widoki Headers, Response i Initiator, w których to jest, a odpowiedniki w innych przeglądarkach pokazują te same pola.

Krok 2: potwierdź, że to żądanie, o którym myślisz

Zaskakująco wiele błędów JSON to w rzeczywistości błędy routingu. Jeśli obsługa wysyłania zgłosi wyjątek, zanim wywoła preventDefault, przeglądarka wykona natywny POST formularza na adres z atrybutu action, a serwer odpowie pełną stroną HTML. Obsługa nigdy się nie wykona, więc JSON nigdy nie został zażądany.

Porównaj URL z panelu z URL-em, który wywołuje twój JavaScript. Szukaj przekierowania kończącego się gdzie indziej, brakującego lub zbędnego ukośnika na końcu, niezgodności metody, gdy obsługa wysyła GET, a punkt końcowy przyjmuje POST, albo formularza wysyłającego na ścieżkę względną ze strony, która się przeniosła. Śledź łańcuch przekierowań do końca i zanotuj końcowy URL, nie pierwszy.

Potem sprawdź inicjatora. Jeśli żądanie przyszło z nawigacji dokumentu, a nie ze skryptu, problem już znalazłeś i żadna zmiana parsera odpowiedzi nie pomoże.

Krok 3: zaklasyfikuj wynik do czterech kategorii

Każdy wynik należy dokładnie do jednej z nich, a kategoria decyduje, gdzie patrzeć dalej.

What you seeCategoryWhere to look
Request never finishes, TLS or connection errorNo usable responseEndpoint reachability, certificate, front-end timeout
Request completes, script gets an opaque failureAccess blockedCross-origin policy, credentials mode, missing response header
200 with an HTML body or a login formWrong representationRedirect, expired session, route fallback, error handler
Body begins with a notice then valid JSONWrong representationServer-side warning output before serialisation
Valid JSON, framework rejects itContract mismatchEnvelope shape, field names, value types

Środkowe wiersze są najczęściej mylnie diagnozowane, bo status to 200. Strona logowania osiągnięta po przekierowaniu to całkowicie dobra odpowiedź HTTP i bardzo zły dokument JSON. Typ zawartości application/json tego nie naprawia: to etykieta, a źle oznaczona treść nadal się nie parsuje. Dostęp zablokowany to wiersz, który wygląda na ukończone żądanie: panel pokazuje status, ale polityka różnych źródeł wstrzymuje treść, więc dla wywołującego skryptu jest tak bezużyteczna jak przekroczenie czasu.

Czwarty wiersz jest równie częsty na starszych stosach PHP i frameworków. Ostrzeżenie o przestarzałości wypisane przed zakodowanym ładunkiem daje treść, której nie przyjmie żaden parser JSON, a często to ostrzeżenie jest całym wyjaśnieniem.

Krok 4: czytaj błąd parsera dosłownie

Tekst błędu wskazuje pierwszy znak, który złamał parsowanie, a to zwykle identyfikuje kategorię bez żadnego zgadywania.

Error text (Chrome/V8)What it means
Unexpected token < in JSON at position 0The body starts with markup: an HTML page or an error document
Unexpected end of JSON inputEmpty body, or the response was truncated
Unexpected token o in JSON at position 1You parsed something already parsed, typically an object rather than text
Unexpected token uThe body starts with the bare word undefined, usually an empty response rendered as a string

Pusta treść ze statusem 200 to osobny przypadek: punkt końcowy zadziałał, nic nie wytworzył, a coś dalej uznało to za sukces. To awaria kontraktu aplikacji, nie transportu, i jej miejsce jest w następnym kroku, nie w pośredniku. Firefox i Safari formułują te same cztery awarie inaczej, więc dopasowuj po znaku albo po pustej treści, a nie po dokładnym ciągu.

Krok 5: napraw warstwę, na którą wskazują dowody

Przy problemie routingu napraw żądanie: popraw action, nie pozwól obsłudze przelecieć, dopasuj punkt końcowy i metodę, a potem przetestuj ponownie. Przy problemie reprezentacji napraw to, co wytworzyło treść, i ustal, dlaczego dokument błędu wraca tam, gdzie oczekiwano danych. Przy problemie kontraktu przeczytaj rzeczywistą oczekiwaną strukturę frameworka dla wersji, którą uruchamiasz, i uformuj odpowiedź według niej, zamiast poluzowywać klienta.

Odpowiedź z zablokowanym dostępem wymaga własnego przebiegu, bo samo żądanie może być poprawne, a treść może nigdy nie dotrzeć do twojego kodu. Porównaj Access-Control-Allow-Origin odpowiedzi z dokładnym Origin wysłanym przez przeglądarkę i pamiętaj, że wieloznacznik nie spełnia żądania z poświadczeniami. Połącz credentials: 'include' po stronie klienta z Access-Control-Allow-Credentials: true po stronie serwera i sprawdź, czy wywołanie nie użyło trybu no-cors, w którym nieprzejrzysta treść jest udokumentowanym wynikiem, a nie usterką.

Zastąpienie parsera czymś łagodniejszym to jedyna naprawa, której należy unikać. Ocena odpowiedzi jako kodu albo zdejmowanie tekstu, aż da się sparsować, ukrywa niezgodność kontraktu i dodaje powierzchnię wstrzyknięcia w zamian za ciszę. Podobnie status trzeba sprawdzać osobno od treści: 200 z obiektem błędu na poziomie aplikacji jest normalne w wielu API i trzeba to obsłużyć, czytając ładunek.

Kiedy potrzebujesz pomocy kogoś innego, udostępnij minimalny zapis — metodę, URL, status, końcowy URL po przekierowaniach, typ zawartości odpowiedzi, kształt treści i oczekiwany kontrakt — a nie surowy eksport. Archiwa sieci zawierają ciasteczka, tokeny, ciągi zapytań i dane osobowe, które były w formularzu, a automatyczny czyściciel nie jest przeglądem.

  • Przechwyć żądanie bez filtra, zanim zmienisz jakikolwiek kod.
  • Potwierdź, że inicjatorem był twój skrypt, a końcowy URL to twój punkt końcowy.
  • Zaklasyfikuj odpowiedź, zanim dotkniesz parsera.
  • Napraw routing, dostęp, reprezentację albo kontrakt i nigdy przez poluzowanie parsera.

Powiązane artykuły