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:
methoddomyślnie ma wartość"GET". Ustaw ją jawnie dla POST, PUT, DELETE, PATCH.bodyprzyjmuje string (alboFormData,Blobitd.): fetch nie zserializuje obiektów za ciebie.JSON.stringify(...)to twoje zadanie.- Nagłówek
Content-Typemó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.