Einführung in "fetch()"

Matt Gaunt

Mit fetch() können Sie Netzwerkanfragen ähnlich wie XMLHttpRequest (XHR) stellen. Der Hauptunterschied besteht darin, dass die Fetch API Promises verwendet, die eine einfachere API haben, um die komplizierten Callbacks in der XMLHttpRequest API zu vermeiden.

Unterstützte Browser

  • Chrome: 42.
  • Edge: 14.
  • Firefox: 39.
  • Safari: 10.1.

Quelle

Wenn Sie Promises noch nie verwendet haben, lesen Sie den Artikel Einführung in JavaScript-Promises.

Hier ist ein Beispiel, das mit XMLHttpRequest und dann mit fetch implementiert wurde. Wir möchten eine URL anfordern, eine Antwort erhalten und sie als JSON parsen.

XMLHttpRequest

Für eine XMLHttpRequest sind zwei Listener erforderlich, um den Erfolg und den Fehlerfall zu behandeln, sowie ein Aufruf von open() und send(). Beispiel aus den MDN-Dokumenten

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

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

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

Abrufen

Unsere Abrufanfrage sieht so aus:

fetch('./api/some.json')
  .then(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(err => {
    console.log('Fetch Error :-S', err);
  });

Für die fetch()-Anfrage ist nur ein Aufruf erforderlich, um die gleiche Arbeit wie im XHR-Beispiel zu erledigen. Um die Antwort zu verarbeiten, prüfen wir zuerst, ob der Antwortstatus 200 ist, und parsen die Antwort dann als JSON. Die Antwort auf eine fetch()-Anfrage ist ein Stream-Objekt. Das bedeutet, dass nach dem Aufrufen der json()-Methode ein Promise zurückgegeben wird. Der Stream erfolgt asynchron.

Antwortmetadaten

Im vorherigen Beispiel wurde der Status des Objekts Response gezeigt und es wurde gezeigt, wie die Antwort als JSON geparst wird. So verarbeiten Sie andere Metadaten, auf die Sie möglicherweise zugreifen möchten, z. B. Header:

fetch('users.json').then(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 der Antwort eine response.type von „basic“, „cors“ oder „opaque“ zugewiesen. Mit diesen types wird angegeben, woher die Ressource stammt. Sie können sie verwenden, um zu bestimmen, wie das Antwortobjekt behandelt werden soll.

Wenn der Browser eine Ressource am selben Ursprung anfordert, hat die Antwort den Typ basic mit Einschränkungen dafür, was Sie in der Antwort sehen können.

Wenn eine Anfrage für eine Ressource an einem anderen Ursprung gesendet wird und dieser Ursprung CORS-Header zurückgibt, ist der Typ cors. cors-Antworten ähneln basic-Antworten, aber die zu sehenden Header sind auf Cache-Control, Content-Language, Content-Type, Expires, Last-Modified und Pragma beschränkt.

opaque-Antworten stammen aus einem anderen Ursprung, der keine CORS-Header zurückgibt. Bei einer undurchsichtigen Antwort können wir die zurückgegebenen Daten nicht lesen oder den Status der Anfrage prüfen. Sie können also nicht überprüfen, ob der Antrag erfolgreich war.

Sie können einen Modus für eine Abrufanfrage definieren, sodass nur bestimmte Anfragetypen aufgelöst werden. Sie können folgende Modi festlegen:

  • same-origin ist nur für Anfragen nach Assets mit demselben Ursprung erfolgreich. Alle anderen Anfragen werden abgelehnt.
  • cors erlaubt Anfragen für Assets mit demselben Ursprung und anderen Ursprüngen, die die entsprechenden CORS-Header zurückgeben.
  • cors-with-forced-preflight führt vor jeder Anfrage eine Preflight-Prüfung durch.
  • no-cors ist dazu gedacht, Anfragen an andere Ursprünge zu senden, die keine CORS-Header haben, und zu einer opaque-Antwort führen. Allerdings ist dies derzeit im globalen Fensterbereich nicht möglich, wie bereits erwähnt.

Um den Modus zu definieren, fügen Sie 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(response => response.text())
  .then(text => {
    console.log('Request successful', text);
  })
  .catch(error => {
    log('Request failed', error)
  });

Verkettung von Versprechen

Eine der großen Vorteile von Versprechen ist die Möglichkeit, sie zu verketten. Bei fetch() können Sie hiermit die Logik für alle Abrufanfragen freigeben.

Wenn Sie mit einer JSON API arbeiten, müssen Sie den Status prüfen und den JSON-Code für jede Antwort parsen. Sie können Ihren Code vereinfachen, indem Sie den Status und das JSON-Parsen in separaten Funktionen definieren, die Versprechen zurückgeben, und die Abrufanfrage nur für die endgültigen Daten und den Fehlerfall verwenden.

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(data => {
    console.log('Request succeeded with JSON response', data);
  }).catch(error => {
    console.log('Request failed', error);
  });

In diesem Beispiel wird eine status-Funktion definiert, die response.status prüft und entweder ein aufgelöstes Promise als Promise.resolve() oder ein abgelehntes Promise als Promise.reject() zurückgibt. Dies ist die erste Methode, die in der fetch()-Kette aufgerufen wird.

Wenn das Promise erfüllt ist, ruft das Script die json()-Methode auf, die ein zweites Promise vom response.json()-Aufruf zurückgibt und ein Objekt mit dem geparsten JSON erstellt. Wenn das Parsing fehlschlägt, wird das Promise abgelehnt und die Catch-Anweisung wird ausgeführt.

Mit dieser Struktur können Sie die Logik für alle Abrufanfragen verwenden, was die Pflege, Lesbarkeit und Testbarkeit des Codes erleichtert.

POST-Anfrage

Manchmal muss eine Webanwendung eine API mit einer POST-Methode aufrufen und einige Parameter in den Text der Anfrage aufnehmen. Legen Sie dazu die Parameter method und body in den fetch()-Optionen fest:

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

Anmeldedaten mit einer Abrufanfrage senden

Wenn du eine Abrufanfrage mit Anmeldedaten wie Cookies senden möchtest, setze den credentials-Wert der Anfrage auf "include":

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