Einführung in die JavaScript Fetch API
Im Vergleich zu XMLHttpRequest und den darauf basierenden Bibliotheken, wie z. B. JQuery.ajax, definiert die Fetch-API eine modernere und sauberere Art der Ausführung asynchroner Anforderungen, basierend auf der Verwendung von Zusagen. In diesem Artikel sehen wir uns einige der von der API bereitgestellten Schnittstellen an, z. B. Request und Response, und wir lernen, wie Sie die fetch-Methode verwenden, um verschiedene Arten von asynchronen Anfragen auszuführen.
In diesem Tutorial lernen Sie:
- So senden Sie asynchrone Anforderungen mit der fetch-Methode
- Arbeiten mit den Anforderungs- und Antwortobjekten, die von der fetch-API bereitgestellt werden
Verwendete Softwareanforderungen und Konventionen
Grundlegende Verwendung
Die Fetch-API stellt HTTP-Anforderungen und -Antworten mithilfe von Anforderungs- und Antwortschnittstellen dar und stellt die Fetch-Methode zum asynchronen Senden von Anforderungen bereit. Beginnen wir mit einem wirklich grundlegenden Beispiel für die Verwendung.
Die fetch-Methode verfügt nur über ein obligatorisches Argument, bei dem es sich entweder um den Pfad der abzurufenden Ressource oder um ein Request-Objekt handelt. Wenn nur dieser Parameter an die Funktion übergeben wird, wird eine GET-Anforderung ausgeführt, um die angegebene Ressource abzurufen. Für dieses Beispiel verwenden wir den NASA-API-Aufruf, der Informationen über das astronomische "Bild des Tages" im JSON-Format zurückgibt. Hier ist unser Code:
fetch('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY')
.then(response => response.json())
.then(json_object => console.log(json_object))
.catch(reason => console.log(reason))Lassen Sie uns kurz erklären, wie der obige Code funktioniert. Die fetch-Funktion gibt ein Promise zurück: Wenn dieses Promise erfüllt ist, wird es in ein Response-Objekt aufgelöst, das die HTTP-Antwort auf die von uns gesendete Anfrage darstellt.
Die then-Methode des Promise-Objekts wird aufgerufen, wenn das Promise den Status "Ausstehend" aufweist. Denken wir daran, dass die Methode sich selbst eine neue Zusage zurückgibt und bis zu zwei Callbacks als Argumente akzeptiert: Der erste wird aufgerufen, wenn die Zusage erfüllt ist; die zweite, wenn sie abgelehnt wird. Hier haben wir nur die erste bereitgestellt, da wir zu diesem Zweck die catch-Methode verwendet haben (wir werden gleich über die Behandlung von Fehlern sprechen).
Der Callback, der als erstes Argument der then-Methode verwendet wird, verwendet den Erfüllungswert der Zusage als Argument, in diesem Fall das Response-Objekt. Dieses Objekt hat unter anderem eine Methode namens json(), die wir im Text des Callbacks aufrufen. Wozu dient diese Methode? Er liest den Antwortstream bis zum Ende und gibt sich selbst ein Promise zurück, das aufgelöst wird, wobei der Text der Antwort als JSON analysiert wird.
Wie wir wissen, wird, wenn eine Handler-Funktion der then-Methode eine Zusage zurückgibt, der Erfüllungswert dieser Zusage als Erfüllungswert der Zusage verwendet, die von der then-Methode selbst zurückgegeben wird. Aus diesem Grund steht das JSON-Objekt als Argument des ersten Callbacks der zweiten then-Methode im Beispiel zur Verfügung. All dies geschieht asynchron. Hier ist das Ergebnis der Ausführung des Codes:
{
"copyright": "Emilio Rivero Padilla",
"date": "2019-05-21",
"explanation": "These three bright nebulae are often featured on telescopic
tours of the constellation Sagittarius and the crowded starfields of the central
Milky Way. In fact, 18th century cosmic tourist Charles Messier cataloged two of
them; M8, the large nebula just left of center, and colorful M20 on the top
left. The third emission region includes NGC 6559 and can be found to the right
of M8. All three are stellar nurseries about five thousand light-years or so
distant. Over a hundred light-years across, the expansive M8 is also known as
the Lagoon Nebula. M20's popular moniker is the Trifid. Glowing hydrogen gas
creates the dominant red color of the emission nebulae. In striking contrast,
blue hues in the Trifid are due to dust reflected starlight. Recently formed
bright blue stars are visible nearby. The colorful composite skyscape was
recorded in 2018 in Teide National Park in the Canary Islands, Spain.",
"hdurl": "https://apod.nasa.gov/apod/image/1905/M8M20_Padilla_1534.avif",
"media_type": "image",
"service_version": "v1",
"title": "Deep Field: Nebulae of Sagittarius",
"url": "https://apod.nasa.gov/apod/image/1905/M8M20_Padilla_960.avif"
}Im obigen Beispiel haben wir den Text der Antwort als JSON analysiert. Es gibt Fälle, in denen wir den Antworttext anders analysieren möchten. Einige Methoden, die uns in diesen Fällen helfen können, sind:
Response.blob(): Nimmt einen Antwortstream und liest ihn bis zu seinem Ende. Gibt eine Zusage zurück, die in einBlob-Objektaufgelöst wird, bei dem es sich um ein dateiähnliches Objekt mit unveränderlichen Rohdaten handelt.Response.text(): liest einen Antwortstream und gibt eine Zusage zurück, die in Text aufgelöst wird, insbesondere in einUSVString-Objekt.Response.formData(): liest einen Antwortstream und gibt eine Zusage zurück, die in einFormData-Objektaufgelöst wird, das Formularfelder und deren Werte darstellt.Response.arrayBuffer():Liest einen Antwortstream und gibt eine Zusage zurück, die in einArrayBuffer-Objektaufgelöst wird, das zur Darstellung von Binärrohdaten verwendet wird.
Komplexere Anfragen senden
Der, den wir oben gesehen haben, war der einfachste mögliche Anwendungsfall der Fetch-Methode. Es gibt Fälle, in denen wir komplexere Anfragen definieren und senden müssen. Wir haben zwei Möglichkeiten, die Aufgabe zu erfüllen: Die erste besteht darin, der fetch-Methode, ein init-Objekt, einen zweiten Parameter zur Verfügung zu stellen; Die zweite beinhaltet die explizite Erstellung eines Request-Objekts, das dann als Argument an die fetch-Methode übergeben wird. Schauen wir uns beide an.
Bereitstellen von Anforderungseinstellungen
Angenommen, wir möchten eine POST-Anforderung ausführen und einige Daten an einen bestimmten Speicherort senden. Wenn wir die Parameter angeben möchten, die zum Ausführen dieser Aufgabe erforderlich sind, können wir beim Ausführen der fetch-Methode ein zweites Argument an sie übergeben, bei dem es sich um ein Objekt handelt, mit dem wir benutzerdefinierte Einstellungen auf die Anfrage anwenden können. Wir können schreiben:
fetch('https://httpbin.org/post', {
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json'}),
body: JSON.stringify({'Name': 'Frodo', 'Lastname': 'Baggins'})
}) Genau wie oben stellt das erste Argument der fetch-Methode das Ziel der Anforderung dar. In diesem Fall senden wir unsere Anfrage an https://httpbin.org/post, bei dem es sich um einen Endpunkt handelt, der vom httbin.org Dienst zum Testen von POST-Anforderungen bereitgestellt wird.
Das optionale zweite Argument der Funktion ist, wie wir oben gesagt haben, ein Objekt, das wir verwenden können, um zusätzliche Parameter für die Anfrage anzugeben. In diesem Fall haben wir zunächst das HTTP-Verb angegeben, das für die Anfrage (POST) verwendet werden soll. Danach haben wir eine weitere Schnittstelle verwendet, die von der fetch-API bereitgestellt wird, Headers, die Methoden und Eigenschaften enthält, die zum Bearbeiten von Anfragen und Antwortheadern nützlich sind. In diesem Fall setzen wir einfach den Header-Parameter 'Content-Type' und deklarieren den Typ des Inhalts, der von unseren Anfragen als application/json übertragen wird. Schließlich definierten wir den eigentlichen Text der Anfrage: Wir verwendeten die stringify-Methode des JSON-Objekts, um ein Objekt in einen JSON-String zu konvertieren.
Wenn Sie den obigen Code ausführen, wird eine POST-Anforderung an die von uns angegebene URL gesendet. Der httpbin.org-Dienst gibt in diesem Fall eine Antwort zurück, die selbst den Inhaltstyp "application/json" hat und die Daten beschreibt, die wir mit unserer Anfrage gesendet haben:
fetch('https://httpbin.org/post', {
method: 'POST',
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({'Name': 'Frodo', 'Lastname': 'Baggins'})
})
.then(response => response.json())
.then(json_object => console.log(json_object))Das Ergebnis ist, wie wir oben sagten, eine Beschreibung unserer Anfrage:
{
"args": {},
"data": "{\"Name\":\"Frodo\",\"Lastname\":\"Baggins\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-US,en;q=0.5",
"Content-Length": "37",
"Content-Type": "application/json",
"Dnt": "1",
"Host": "httpbin.org",
"Origin": "http://localhost:8080",
"Referer": "http://localhost:8080/",
"User-Agent": "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:66.0)
Gecko/20100101 Firefox/66.0"
},
"json": {
"Lastname": "Baggins",
"Name": "Frodo"
},
"origin": "xx.xx.xx.xx, xx.xx.xx.xx",
"url": "https://httpbin.org/post"
}Manuelles Erstellen eines Request-Objekts
Als Alternative zum obigen Code können wir explizit ein Request-Objekt erstellen und es dann an die fetch-Methode übergeben:
let request = new Request('https://httpbin.org/post', {
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json'}),
body: JSON.stringify({'Name': 'Frodo', 'Lastname': 'Baggins'})
})Um es mit fetch zu senden, schreiben wir einfach:
fetch(request)
.then(response => response.json())
.then(json_object => console.log(json_object))
Fehlerbehandlung
Ein grundlegender Unterschied zwischen dem Verhalten der fetch-Methode und JQuery.ajax() ist die Art und Weise, wie eine Antwort mit einem HTTP-Fehlerstatus (ein Statuscode, der nicht im Bereich von 200 bis 299 liegt) behandelt wird. In einem solchen Fall wird bei Verwendung der fetch-Methode das von ihr zurückgegebene Versprechen weiterhin als erfüllt betrachtet. Der einzige Fall, in dem die Zusage abgelehnt wird, ist, wenn ein Kommunikationsfehler vorliegt und die Anforderung ihr Ziel nicht erreichen kann.
Lassen Sie es uns anhand eines Beispiels verdeutlichen. Wenn wir weiterhin den httpbin.org-Dienst verwenden, senden wir eine GET-Anforderung an den Endpunkt "https://httpbin.org/post", den wir im vorherigen Beispiel verwendet haben und der nur POST-Anforderungen akzeptiert. Zuerst sehen wir, was passiert, wenn JQuery.ajax() verwendet wird:
$.ajax({type: 'get', url: 'https://httpbin.org/post'})
.then(() => console.log('The promise was fulfilled!'))
.catch(jqXHR => console.log(`Promise rejected because status code was ${jqXHR.status}`))Der obige Code gibt Folgendes zurück:
Promise rejected because status code was 405Dies gibt an, dass die Zusage abgelehnt wurde und daher der Rückruf der catch-Methode aufgerufen wurde. Wenn dieselbe Anforderung mit der fetch-Methode gesendet wird, wird die resultierende Zusage nicht abgelehnt:
fetch('https://httpbin.org/post')
.then(response => console.log(`Promise has been fulfilled even if response status is ${response.status}`))
.catch(reason => console.log('Promise has been rejected!'))Das Ergebnis des Ausführens des obigen Codes lautet:
Promise has been fulfilled even if response status is 405Was ist passiert? Da wir ein HTTP-Verb "Nicht zulässig" für den angegebenen Endpunkt verwendet haben, erhielten wir eine Antwort mit dem Statuscode "Methode nicht zulässig" (405). Dies führte jedoch nicht dazu, dass die Zusage abgelehnt wurde, und der Rückruf der then-Methode wurde aufgerufen. Wenn wir den gleichen Code ausprobieren, der nur das Anforderungsziel in einen nicht vorhandenen Pfad, 'https://foo.bar', ändert, gibt der Code Folgendes zurück:
Promise has been rejected!Diesmal wurde der Callback aufgerufen, der als Argument der catch-Methode verwendet wurde. Es ist sehr wichtig, sich an dieses Verhalten zu erinnern: Die von der fetch-Methode zurückgegebene Zusage wird nur dann abgelehnt, wenn die Kommunikation mit dem Server fehlschlägt und die Anfrage nicht abgeschlossen werden kann. Um absolut sicher zu sein, dass unsere Anfrage erfolgreich ist, müssen wir den Statuscode des Response-Objekts überprüfen, der in seiner status-Eigenschaft verfügbar ist, oder die schreibgeschützte Eigenschaft ok testen, die einen booleschen Wert enthält, der angibt, ob das Ergebnis erfolgreich war oder nicht.
Schlüsse
In diesem Tutorial haben wir die Javascript-Fetch-API kennengelernt und gesehen, wie wir sie als Alternative zu anderen Methoden zum Ausführen asynchroner Anfragen wie JQuery.ajax verwenden können. Wir haben gesehen, wie man grundlegende Anfragen durchführt und wie man komplexere Anfragen erstellt. Wir haben auch untersucht, wie sich die von der fetch-Methode zurückgegebene Zusage verhält, wenn eine Antwort mit einem Statuscode außerhalb des Bereichs von 200 bis 299 empfangen wird und wenn ein Verbindungsfehler auftritt. Um mehr über die fetch-API zu erfahren, können Sie die Mozilla-Webdokumentation konsultieren.