Menu

Fetch API w JavaScript: żądania, JSON i obsługa błędów

Jak używać Fetch API w JavaScript: żądania GET i POST, parsowanie JSON, poprawna obsługa błędów i przerywanie wolnych żądań.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Fetch to klient HTTP oparty na obietnicach

fetch jest wbudowany w przeglądarki i nowoczesny Node. Podajesz mu URL, a on zwraca Promise, który rozwiązuje się do obiektu Response. W swej istocie to całe API:

Dwa wywołania .then, bo są dwa asynchroniczne kroki: najpierw przychodzą nagłówki odpowiedzi (tym rozwiązuje się pierwsza obietnica), potem treść zostaje odczytana i sparsowana (response.json() samo jest obietnicą). Treść nie jest pobierana, dopóki o nią nie poprosisz.

Ten sam przepływ z async/await czyta się jak zwykły kod z góry na dół:

Dwa await, dwa punkty wstrzymania. Ta sama praca, czytelniejsza kolejność.

Obiekt Response

To, co dostajesz z powrotem, nie jest treścią, tylko obiektem Response z metadanymi i metodami do odczytu treści w różnych formach:

Treść możesz odczytać przez .json(), .text(), .blob(), .arrayBuffer() lub .formData(). Każda z tych metod zwraca obietnicę. Treść da się odczytać tylko raz: wywołaj .json() dwa razy na tej samej odpowiedzi, a drugie wywołanie rzuci błąd.

Wielka pułapka: błędy HTTP nie odrzucają obietnicy

Na tym potyka się prawie każdy, kto zaczyna z fetch. Odpowiedź 404 czy 500 nie jest odrzuceniem. Obietnica rozwiązuje się normalnie, z response.ok === false. Fetch odrzuca obietnicę tylko wtedy, gdy samego żądania nie dało się wykonać: awaria DNS, brak sieci, blokada CORS.

To znaczy, że naiwny fetch chętnie poda ci stronę błędu i wysypie się później na .json():

Poprawka to samodzielne sprawdzenie response.ok i rzucenie błędu, jeśli serwer zwrócił status błędu:

Przyzwyczaj się do pisania tego bloku if (!response.ok). Powinien się znaleźć w każdym opakowaniu fetch, które napiszesz.

Wysyłanie żądania POST

Domyślnie jest GET. Do wszystkiego innego przekaż drugi argument, obiekt opcji:

Trzy rzeczy warte uwagi:

  • method domyślnie ma wartość "GET". Ustaw ją jawnie dla POST, PUT, DELETE, PATCH.
  • body przyjmuje string (albo FormData, Blob itd.): fetch nie zserializuje obiektów za ciebie. JSON.stringify(...) to twoje zadanie.
  • Nagłówek Content-Type mówi serwerowi, jak parsować treść. Zapomnisz o nim, a większość serwerów potraktuje treść jak zwykły tekst.

Nagłówki, query stringi i inne opcje

Nagłówki to po prostu obiekt (albo instancja Headers). Query stringi budujesz sam, zwykle przez URLSearchParams:

URLSearchParams zajmuje się kodowaniem za ciebie (spacje, znaki &, unicode), więc nie skończysz z zepsutymi adresami URL, gdy dane wejściowe zawierają znaki wymagające escapowania.

Inne opcje, które zobaczysz w prawdziwym kodzie: credentials: "include", żeby wysyłać ciasteczka między domenami, cache: "no-store", żeby ominąć cache HTTP, mode: "cors" (zwykle domyślne) do sterowania zachowaniem CORS.

Anulowanie żądania przez AbortController

Czasem chcesz zrezygnować: użytkownik wpisał nowe zapytanie wyszukiwania albo żądanie trwa za długo. Służy do tego AbortController:

controller.abort() sprawia, że obietnica fetch zostaje odrzucona z DOMException, którego name to "AbortError". Blok finally czyści timeout, żeby udane żądanie nie zostawiało wiszącego timera.

Ten wzorzec, czyli fetch z timeoutem i sprzątaniem, warto opakować w funkcję pomocniczą i używać wszędzie.

Opakowanie wielokrotnego użytku

Połącz to wszystko, a dostaniesz małą funkcję pomocniczą, która raz na zawsze załatwia szablonowy kod:

Jedno miejsce do zmiany nagłówków, jedno do obsługi błędów, jedno do radzenia sobie z pustymi odpowiedziami. Każda nietrywialna aplikacja w końcu ma coś takiego.

Dalej: obsługa błędów w kodzie asynchronicznym

Fetch to jedno z najczęstszych miejsc, w których wychodzą błędy asynchroniczne, a sprawdzenie response.ok to tylko jeden element układanki. Następna strona dotyczy obsługi błędów w obietnicach i async/await: dokąd trafiają błędy, jak je łapać i jakie pułapki pozwalają im po cichu się prześlizgnąć.

Najczęściej zadawane pytania

Jak używać fetch w JavaScript?

Wywołaj fetch(url) z adresem, którego potrzebujesz. Zwraca Promise, który rozwiązuje się do obiektu Response. Wywołaj response.json() (również obietnica), żeby sparsować treść. Z async/await: const res = await fetch(url); const data = await res.json();.

Jak wysłać żądanie POST przez fetch?

Przekaż drugi argument z method: 'POST', obiektem headers (zwykle 'Content-Type': 'application/json') i body: obiekty zamień na string przez JSON.stringify(...). Fetch nie zserializuje treści za ciebie.

Dlaczego fetch nie odrzuca obietnicy przy 404 lub 500?

Fetch odrzuca obietnicę tylko przy awariach sieci: błędach DNS, braku połączenia, blokadzie CORS. Statusy błędów HTTP to z punktu widzenia obietnicy nadal udane odpowiedzi. Musisz sam sprawdzić response.ok (true dla statusów od 200 do 299) albo response.status i rzucić błąd, jeśli serwer zwrócił błąd.

Czy mogę anulować żądanie fetch?

Tak, przez AbortController. Utwórz go, przekaż jego signal do fetch w obiekcie opcji i wywołaj controller.abort(), gdy chcesz anulować żądanie. Obietnica fetch zostanie odrzucona z AbortError, który możesz obsłużyć w catch.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ