Wprowadzenie do pobierania()

Interfejs fetch() API trafia do obiektu window i chce zastąpić wskaźniki XHR

Tak długo XMLHttpRequest

fetch() umożliwia generowanie żądań sieciowych podobnych do XMLHttpRequest (XHR). Główna różnica polega na tym, że interfejs Fetch API korzysta z Promises. Jest to prostszy i bardziej przejrzysty interfejs API, co pozwala uniknąć zjawiska zwrotnego i konieczności zapamiętania złożonego interfejsu API XMLHttpRequest.

Obsługa przeglądarek

  • 42
  • 14
  • 39
  • 10.1

Źródło

Interfejs Fetch API jest dostępny w zakresie globalnym Service Worker od Chrome 40, ale w Chrome 42 będzie włączony w zakresie okien. Jest też dostępny do pobrania kod polyfill z GitHub.

Jeśli nie znasz jeszcze pozycji Promises, zapoznaj się z artykułem Wprowadzenie do obietnic związanych z JavaScriptem.

Podstawowe żądanie pobierania

Zacznijmy od porównania prostego przykładu zaimplementowanego z elementem XMLHttpRequest, a następnie z elementem fetch. Chcemy tylko wysłać żądanie URL-a, otrzymać odpowiedź i przeanalizować go jako JSON.

XMLHttpRequest

Element XMLHttpRequest wymaga skonfigurowania 2 detektorów tak, aby obsługiwały przypadki sukcesu i błędów, oraz wywołanie open() i send(). Przykład z dokumentacji MDN

function reqListener() {
    var data = JSON.parse(this.responseText);
    console.log(data);
}

function reqError(err) {
    console.log('Fetch Error :-S', err);
}

var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

Pobierz

Nasze żądanie pobierania wygląda mniej więcej tak:

fetch('./api/some.json')
    .then(
    function(response) {
        if (response.status !== 200) {
        console.log('Looks like there was a problem. Status Code: ' +
            response.status);
        return;
        }

        // Examine the text in the response
        response.json().then(function(data) {
        console.log(data);
        });
    }
    )
    .catch(function(err) {
    console.log('Fetch Error :-S', err);
    });

Zaczynamy od sprawdzenia, czy odpowiedź ma stan 200, zanim przeanalizujemy ją w formacie JSON.

Odpowiedź żądania fetch() jest obiektem Stream, co oznacza, że wywołanie metody json() powoduje zwracanie obietnicy, ponieważ odczyt strumienia jest asynchronicznie.

Metadane odpowiedzi

W poprzednim przykładzie przeanalizowaliśmy stan obiektu Response oraz sposób analizowania odpowiedzi jako JSON. Inne metadane, do których możemy mieć dostęp, np. nagłówki, są przedstawione poniżej.

fetch('users.json').then(function(response) {
    console.log(response.headers.get('Content-Type'));
    console.log(response.headers.get('Date'));

    console.log(response.status);
    console.log(response.statusText);
    console.log(response.type);
    console.log(response.url);
});

Typy odpowiedzi

Po wysłaniu żądania pobierania odpowiedź otrzymuje response.typebasic”, „cors” lub „opaque”. Te znaki types wskazują, skąd pochodzi zasób i można ich użyć, aby poinformować, jak należy traktować obiekt odpowiedzi.

Po wysłaniu żądania dotyczącego zasobu z tego samego źródła odpowiedź będzie miała typ basic i nie ma żadnych ograniczeń dotyczących tego, co można w niej zobaczyć.

Jeśli zostanie wysłane żądanie zasobu z innego źródła, które zwraca nagłówki COR, typ to cors. Odpowiedzi cors i basic są prawie identyczne z tą różnicą, że odpowiedź cors ogranicza widoczne nagłówki do Cache-Control, Content-Language, Content-Type, Expires, Last-Modified i Pragma.

Odpowiedź opaque dotyczy żądania wysłanego do zasobu w innym źródle, które nie zwraca nagłówków CORS. W przypadku nieprzejrzystej odpowiedzi nie możemy odczytać zwróconych danych ani wyświetlić stanu żądania, co oznacza, że nie będziemy mogli sprawdzić, czy żądanie zostało zrealizowane.

Możesz zdefiniować tryb żądania pobrania, tak aby rozpoznawane były tylko niektóre żądania. Możesz wybrać te tryby:

  • same-origin spełnia tylko żądania dotyczące zasobów z tego samego źródła, a pozostałe żądania są odrzucane.
  • cors będzie zezwalać na żądania zasobów z tego samego pochodzenia i innych źródeł, które zwracają odpowiednie nagłówki COR.
  • cors-with-forced-preflight zawsze przeprowadza kontrolę wstępną przed wysłaniem rzeczywistego żądania.
  • Funkcja no-cors służy do wysyłania żądań do innych źródeł, które nie mają nagłówków CORS i generują odpowiedź opaque, ale jak wspomnieliśmy, nie jest to obecnie możliwe w globalnym zakresie okna.

Aby zdefiniować tryb, dodaj obiekt opcji jako drugi parametr w żądaniu fetch i określ tryb w tym obiekcie:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
    .then(function(response) {
    return response.text();
    })
    .then(function(text) {
    console.log('Request successful', text);
    })
    .catch(function(error) {
    log('Request failed', error)
    });

Łańcuchy

Jedną z największych zalet przewidywań jest łączenie ich ze sobą. W przypadku pobierania umożliwia to współdzielenie logiki między żądaniami pobierania.

Jeśli korzystasz z interfejsu JSON API, musisz sprawdzić stan i przeanalizować plik JSON w przypadku każdej odpowiedzi. Możesz uprościć kod, definiując stan i analizę JSON w osobnych funkcjach, które zwracają obie wersje. Dzięki temu nie musisz się martwić o obsługę końcowych danych i przypadku błędu.

function status(response) {
    if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
    } else {
    return Promise.reject(new Error(response.statusText))
    }
}

function json(response) {
    return response.json()
}

fetch('users.json')
    .then(status)
    .then(json)
    .then(function(data) {
    console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
    console.log('Request failed', error);
    });

Definiujemy funkcję status, która sprawdza parametr response.status i zwraca wynik Promise.resolve() lub Promise.reject(), które zwracają rozwiniętą lub odrzuconą obietnicę. Jest to pierwsza metoda wywoływana w łańcuchu fetch(). Jeśli się uda, wywołujemy metodę json(), która ponownie zwraca obietnicę z wywołania response.json(). Następnie znajduje się obiekt przeanalizowanego kodu JSON. Jeśli analiza nie powiedzie się, obietnica jest odrzucana, a instrukcja catch jest wykonywana.

Ogromną zaletą jest to, że możesz stosować tę samą logikę we wszystkich żądaniach pobierania, co ułatwia obsługę, odczytywanie i testowanie kodu.

Żądanie POST

Często aplikacje internetowe chcą wywoływać interfejs API za pomocą metody POST i umieszczać w treści żądania pewne parametry.

W tym celu możemy ustawić parametry method i body w opcjach fetch().

fetch(url, {
    method: 'post',
    headers: {
        "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
    })
    .then(json)
    .then(function (data) {
    console.log('Request succeeded with JSON response', data);
    })
    .catch(function (error) {
    console.log('Request failed', error);
    });

Wysyłanie danych logowania za pomocą żądania pobrania

Jeśli chcesz wysłać żądanie pobierania z użyciem danych uwierzytelniających, np. plików cookie, ustaw credentials żądania na "include".

fetch(url, {
    credentials: 'include'
})

Najczęstsze pytania

Jak anulować żądanie fetch()?

W tej chwili nie ma możliwości anulowania pobierania, ale teraz zajmujemy się tym na GitHubie. H/T @jankowalski dla tego linku.

Czy jest dostępny kod polyfill?

GitHub udostępnia kod polyfill do pobierania. H/T @Nexii za zwrócenie uwagi na tę kwestię.

Dlaczego mechanizm „no-cors” jest obsługiwany w instancjach service worker, ale nie w tym oknie?

Ma to na celu zwiększenie bezpieczeństwa. Więcej informacji znajdziesz tutaj.