Einführung in "fetch()"

Die Abruf()-API landet im Fensterobjekt und möchte XHRs ersetzen.

Matt Gaunt

So lang XMLHttpRequest

Mit fetch() können Sie Netzwerkanfragen ähnlich wie XMLHttpRequest (XHR) senden. Der Hauptunterschied besteht darin, dass die Fetch API Promises verwendet. Dadurch wird eine einfachere und sauberere API ermöglicht, wodurch die Callback-Helligkeit vermieden wird und man sich die komplexe API von XMLHttpRequest merken muss.

Unterstützte Browser

  • 42
  • 14
  • 39
  • 10.1

Quelle

Die Fetch API ist seit Chrome 40 im globalen Bereich Service Worker verfügbar, wird aber im Fensterbereich in Chrome 42 aktiviert. Es gibt auch ein abrufendes Polyfill von GitHub, das du schon heute verwenden kannst.

Wenn Sie Promise-Objekte noch nie verwendet haben, sollten Sie die Einführung in JavaScript-Promise-Objekte lesen.

Einfache Abrufanfrage

Vergleichen wir zuerst ein einfaches Beispiel, das mit einem XMLHttpRequest und dann mit fetch implementiert wurde. Wir möchten einfach eine URL anfordern, eine Antwort erhalten und sie als JSON parsen.

XMLHttpRequest

Für XMLHttpRequest müssen zwei Listener festgelegt sein, um die Erfolgs- und Fehlerfälle zu verarbeiten, sowie einen Aufruf von open() und send(). Beispiel aus der MDN-Dokumentation

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();

Abrufen

Unsere Abrufanfrage sieht in etwa so aus:

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);
    });

Wir prüfen zuerst, ob der Antwortstatus 200 ist, bevor wir die Antwort als JSON parsen.

Die Antwort auf eine fetch()-Anfrage ist ein Stream-Objekt. Das bedeutet, dass beim Aufrufen der Methode json() ein Promise zurückgegeben wird, da das Lesen des Streams asynchron erfolgt.

Antwortmetadaten

Im vorherigen Beispiel haben wir den Status des Response-Objekts betrachtet und wissen, wie die Antwort als JSON geparst wird. Andere Metadaten, auf die wir möglicherweise zugreifen möchten, wie z. B. Header, sind unten dargestellt.

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);
});

Antworttypen

Wenn wir eine Abrufanfrage stellen, wird als Antwort als response.typebasic“, „cors“ oder „opaque“ zurückgegeben. Diese types geben an, woher die Ressource stammt, und geben an, wie das Antwortobjekt zu behandeln ist.

Wenn eine Anfrage für eine Ressource am selben Ursprung gesendet wird, hat die Antwort den Typ basic und es gibt keine Einschränkungen im Hinblick darauf, was Sie aus der Antwort sehen können.

Wenn eine Anfrage für eine Ressource von einem anderen Ursprung gesendet wird und die COR-Header zurückgegeben werden, ist der Typ cors. Die Antworten cors und basic sind fast identisch, mit der Ausnahme, dass eine cors-Antwort die angezeigten Header auf Cache-Control, Content-Language, Content-Type, Expires, Last-Modified und Pragma einschränkt.

Eine opaque-Antwort bezieht sich auf eine Anfrage an eine Ressource an einem anderen Ursprung, die keine CORS-Header zurückgibt. Bei einer intransparenten Antwort können wir die zurückgegebenen Daten nicht lesen oder den Status der Anfrage einsehen, d. h. wir können nicht prüfen, ob die Anfrage erfolgreich war oder nicht.

Sie können einen Modus für eine Abrufanfrage definieren, sodass nur bestimmte Anfragen aufgelöst werden. Folgende Modi können festgelegt werden:

  • same-origin ist nur bei Anfragen für Assets desselben Ursprungs erfolgreich. Alle anderen Anfragen werden abgelehnt.
  • cors lässt Anfragen für Assets desselben und anderer Ursprünge zu, die die entsprechenden COR-Header zurückgeben.
  • cors-with-forced-preflight führt immer eine Preflight-Prüfung durch, bevor die eigentliche Anfrage gestellt wird.
  • no-cors ist dazu vorgesehen, Anfragen an andere Ursprünge zu senden, die keine CORS-Header haben und zu einer opaque-Antwort führen. Dies ist jedoch derzeit im globalen Fensterbereich nicht möglich.

Um den Modus zu definieren, fügen Sie in der fetch-Anfrage ein Optionsobjekt als zweiten Parameter hinzu und definieren den Modus in diesem Objekt:

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)
    });

Verkettungen

Eins der großartigen Merkmale von Versprechen ist die Fähigkeit, sie miteinander zu verknüpfen. So können Sie für das Abrufen die Logik für Abrufanfragen freigeben.

Wenn Sie mit einer JSON API arbeiten, müssen Sie den Status prüfen und die JSON für jede Antwort parsen. Sie können Ihren Code vereinfachen, indem Sie den Status und die JSON-Analyse in separaten Funktionen definieren, die Promise zurückgeben. Sie müssen sich dann nur noch um die Verarbeitung der endgültigen Daten und den Fehlerfall kümmern.

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);
    });

Wir definieren die Funktion status, die response.status prüft und das Ergebnis von Promise.resolve() oder Promise.reject() zurückgibt, wodurch ein geklärtes oder abgelehntes Promise zurückgegeben wird. Dies ist die erste Methode, die in unserer fetch()-Kette aufgerufen wird. Wenn sie aufgelöst wird, rufen wir die json()-Methode auf, die wieder ein Promise-Objekt aus dem response.json()-Aufruf zurückgibt. Danach haben wir ein Objekt der geparsten JSON. Wenn das Parsing fehlschlägt, wird das Promise-Objekt abgelehnt und die Catch-Anweisung ausgeführt.

Das Tolle dabei ist, dass Sie die Logik für alle Ihre Abrufanfragen freigeben können. Code lässt sich so leichter verwalten, lesen und testen.

POST-Anfrage

Es ist nicht ungewöhnlich, dass Webanwendungen eine API mit einer POST-Methode aufrufen und einige Parameter im Text der Anfrage angeben.

Dazu können wir die Parameter method und body in den fetch()-Optionen festlegen.

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);
    });

Anmeldedaten mit einer Abrufanfrage senden

Wenn Sie eine Abrufanfrage mit Anmeldedaten wie Cookies stellen möchten, sollten Sie credentials der Anfrage auf "include" setzen.

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

Häufig gestellte Fragen

Wie breche ich einefetch()-Anfrage ab?

Derzeit gibt es keine Möglichkeit, einen Abruf abzubrechen. Dies wird jedoch auf GitHub diskutiert. H/T @jaffathecake für diesen Link.

Gibt es einen Polyfill?

GitHub hat einen Polyfill zum Abrufen. H/T @Nexii für den Hinweis.

Warum wird „no-cors“ in Service Workern unterstützt, aber nicht im Fenster?

Dies ist auf ein Sicherheitsproblem zurückzuführen. Weitere Informationen findest du hier.