Tutorial zur JavaScript-Abruf-API: GET, POST, Fehlerbehandlung und Zeitüberschreitungen

  1. Startseite
  2. Blog
  3. Softwareentwicklung

Softwareentwicklung

JavaScript-Fetch-API-Tutorial: GET, POST, Fehlerbehandlung und Zeitüberschreitungen

Fetch ist die integrierte Methode zum Aufrufen von APIs aus JavaScript, hat jedoch eine Überraschung, die fast jeden anspricht. Erfahren Sie, wie Sie Anfragen senden, mit jeder Art von Fehler umgehen und einen kleinen Helfer erstellen, den Sie wiederverwenden können.

9 Min. Lesezeit
Tutorial zur JavaScript-Fetch-API: GET, POST, Fehlerbehandlung und Zeitüberschreitungen

Das Wichtigste

  • fetch() gibt ein Versprechen für Response zurück, und das Lesen des Körpers dauert eine Sekunde await.
  • HTTP-Fehler wie 404 und 500 werden nicht abgelehnt, also überprüfen Sie immer response.ok.
  • Um JSON zu senden, verwenden Sie JSON.stringify und legen Sie den Header Content-Type fest.
  • Für Fetch gibt es keine Standard-Timeout-Option. Verwenden Sie daher AbortSignal.timeout().

Die meisten modernen Web-Apps kommunizieren ständig mit einem Server. Die JavaScript Fetch API ist die Standardmethode dafür und sie ist in Browser und in Node.js 18 und höher integriert, sodass nichts installiert werden muss.

Die grundlegende Verwendung dauert zwei Zeilen, doch viele Tutorials hören hier auf und lassen den Teil weg, der echte Fehler verursacht: die Fehlerbehandlung. Wir haben die Beispiele in diesem Handbuch auf einem kleinen lokalen Server auf Node.js 24 getestet und die angezeigte Ausgabe stammt von diesem Lauf. example.com im Code steht für Ihre eigene API. Wenn Versprechen für Sie neu sind, beginnen Sie mit der Erklärung von JavaScript-Versprechen.

Was ist die Fetch-API?

Fetch ist eine Promise-basierte Schnittstelle zum Senden von HTTP-Anfragen. Es ersetzte das ältere, rückrufgesteuerte XMLHttpRequest, und viele Projekte verwenden es jetzt, anstatt eine Bibliothek für einfache Aufrufe hinzuzufügen.

Funktion Holen Axios (Bibliothek)
Installation Eingebaut Als Abhängigkeit hinzugefügt
JSON-Körper Stringisieren Sie es selbst Automatisch
JSON-Antwort analysieren Anruf response.json() Automatisch
HTTP-Fehler ablehnen? Nein Ja, standardmäßig
Auszeit Durch AbortSignal Eine timeout Option

Eine GET-Anfrage

Fetch führt standardmäßig eine GET-Anfrage durch. Es gibt zwei Schritte, und jeder benötigt await: Zuerst kommen die Antwortheader an, und dann lesen Sie den Text.

const response = await fetch("https://example.com/users/1");
const user = await response.json();

console.log(user);

// { id: 1, name: 'Asha' }

Die beiden Schritte sind vorhanden, da der Textkörper möglicherweise groß ist und später als die Kopfzeilen eintrifft. In einem Browser-Skript benötigt die oberste Ebene await ein Modul, daher fügen Sie dieses normalerweise in eine async-Funktion ein. Sehen Sie sich unseren JavaScript-Async/Await-Leitfaden an.

Das Response-Objekt

Bevor Sie den Text lesen, können Sie sich die Antwort ansehen:

console.log(response.status, response.ok, response.headers.get("content-type"));

// 200 true application/json
Eigenschaft oder Methode Gibt dir
response.ok true für Status 200 bis 299
response.status Der Statuscode, z. B. 404
response.headers.get(name) Ein Antwortheader
response.json() Der als JSON analysierte Text
response.text() Der Körper als String
response.blob() Binäre Daten, beispielsweise ein Bild

Ein Körper kann nur einmal gelesen werden. Ein zweiter Aufruf von json() schlug in unserem Test fehl:

await res.json();
await res.json();

// TypeError: Body is unusable: Body has already been read

Wenn Sie es zweimal lesen müssen, rufen Sie zuerst response.clone() auf.

Die große Überraschung: Ein 404 wirft nicht

Das ist das Wichtigste in diesem Artikel. Wir haben einen Benutzer angefordert, der nicht existiert:

const res = await fetch("https://example.com/users/999");
console.log(res.status, res.ok);

// 404 false

Es wurde keine Ausnahme ausgelöst. Was den Abruf betrifft, hat die Anfrage funktioniert: Der Server wurde erreicht und er hat geantwortet. Das Versprechen wird nur dann abgelehnt, wenn überhaupt keine brauchbare Antwort eintrifft, beispielsweise bei einem Netzwerkausfall. Code wie dieser hat also einen versteckten Fehler:

try {
  const res = await fetch(url);
  const data = await res.json();   // may be an error payload
  showUser(data);                  // runs anyway for 404 and 500
} catch (error) {
  showError();                     // does not run for 404 or 500
}

Sehen Sie sich unseren Spickzettel für HTTP-Statuscodes an, um zu sehen, was die einzelnen Codes bedeuten.

Ein wiederverwendbarer Helfer

Wiederholen Sie diese Prüfung nicht überall. Wickeln Sie es einmal ein:

async function getJson(url, options) {
  const response = await fetch(url, options);
  if (!response.ok) {
    throw new Error(`Request failed with status ${response.status}`);
  }
  return response.json();
}

try {
  await getJson("https://example.com/users/999");
} catch (error) {
  console.log("caught:", error.message);
}

// caught: Request failed with status 404

Jetzt landen sowohl HTTP-Fehler als auch Netzwerkfehler im selben catch. Diese kleine Funktion lohnt sich in jedem Projekt. Eine echte Version könnte auch eine Fehlermeldung aus dem Antworttext lesen und eine 204 No Content-Antwort verarbeiten, die kein JSON zum Parsen hat.

POST-JSON-Daten

Übergeben Sie ein Optionsobjekt als zweites Argument. Für JSON müssen Sie zwei Dinge selbst tun: die Daten in einen String konvertieren und den Header festlegen.

const created = await getJson("https://example.com/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Ben" }),
});

console.log(created);

// { id: 2, name: 'Ben', type: 'application/json' }

Unser Testserver hat den empfangenen Inhaltstyp zurückgegeben und bestätigt, dass der Header angekommen ist. Das Vergessen dieses Headers ist eine häufige Ursache für verwirrende Serverfehler, da viele Frameworks JSON nur dann analysieren, wenn es deklariert wird. Um ein Formular oder Dateien hochzuladen, übergeben Sie ein FormData-Objekt als Textkörper und setzen Sie nicht Content-Type, da der Browser selbst einen Grenzwert hinzufügen muss.

Andere Methoden und Optionen

Option Beispiel Zweck
Methode "PUT", "PATCH", "DELETE" Die HTTP-Methode
Kopfzeilen { Autorisierung: „Inhaber ...“ } Header anfordern
Körper JSON.stringify(data) Der Anforderungstext
Signal AbortSignal.timeout(5000) Stornieren
Anmeldeinformationen „einschließen“ Ursprungsübergreifendes Senden von Cookies
Cache „kein Laden“ Verhalten des Browser-Cache

Wählen Sie zwischen REST und anderen API-Stilen? Unser Vergleich von REST vs. GraphQL zeigt, wie fetch jeweils zusammenpasst.

Abfragezeichenfolgen

Erstellen Sie Abfragezeichenfolgen nicht durch Zusammenfügen von Text, da diese durch Sonderzeichen unterbrochen werden. URLSearchParams übernimmt die Kodierung für Sie:

const params = new URLSearchParams({ q: "red shoes", page: 2 });
console.log(params.toString());

// q=red+shoes&page=2

await getJson(`https://example.com/search?${params}`);

// { q: 'red shoes', page: '2' }

Der Server hat red shoes korrekt empfangen und der Speicherplatz wurde wiederhergestellt.

Auszeiten und Absagen

Der Abruf wird auf einem langsamen Server lange warten, sofern Sie ihm nichts anderes mitteilen. AbortSignal.timeout() setzt eine Grenze. Unser Testendpunkt benötigte zwei Sekunden gegenüber einem Limit von 200 Millisekunden:

try {
  await fetch("https://example.com/slow", { signal: AbortSignal.timeout(200) });
} catch (error) {
  console.log(error.name);
}

// TimeoutError

Um den Vorgang manuell abzubrechen, beispielsweise wenn ein Benutzer eine Seite verlässt oder einen neuen Suchbegriff eingibt, verwenden Sie eine AbortController:

const controller = new AbortController();
const pending = fetch("https://example.com/slow", { signal: controller.signal });

controller.abort();

try {
  await pending;
} catch (error) {
  console.log(error.name);
}

// AbortError

Um mehrere Anfragen gleichzeitig auszuführen, verwenden Sie Promise.all, was viel schneller ist, als einzeln auf sie zu warten:

const [user, search] = await Promise.all([
  getJson("https://example.com/users/1"),
  getJson("https://example.com/search?q=a&page=1"),
]);

Jede Art von Misserfolg

Hier sehen Sie, wie die einzelnen Fehler in unserem Lauf aussahen und wie man sie voneinander unterscheiden kann:

Situation Was passiert So erkennen Sie es
Der Server gibt 404 oder 500 zurück Versprechen erfüllt response.ok ist falsch
Der Server ist nicht erreichbar Ablehnung mit TypeError fangen
Zeitüberschreitung erreicht Ablehnung mit TimeoutError error.name
Manuell storniert Ablehnung mit AbortError error.name
Der Text ist kein gültiger JSON-Code json() lehnt ab mit SyntaxError fangen

Diese letzte Reihe ist in der Produktion üblich. Ein Proxy, der eine 502 zurückgibt, sendet häufig eine HTML-Fehlerseite. Wir haben dies reproduziert und res.json() hat eine SyntaxError geworfen. Wenn Sie response.ok vor dem Parsen überprüfen, melden Sie das eigentliche Problem und nicht einen verwirrenden Parse-Fehler.

Tipp: Testen Sie diese Fehlerpfade absichtlich. Browser-Entwicklertools können den Offline-Zustand simulieren und Testtools können eine 500-Antwort simulieren. Unser Leitfaden zum API-Testen mit Postman behandelt die Überprüfung der API-Seite.

CORS und Anmeldeinformationen

In einem Browser unterliegt eine Anfrage von einem Ursprung zu einem anderen CORS, den Cross-Origin-Ressourcenfreigaberegeln. Wenn Sie einen Fehler mit der Erwähnung von Access-Control-Allow-Origin sehen, gehört der Fix zum Server, der Ihre Site zulassen muss. In Ihrem JavaScript wird der Fehler nur als generisches Problem angezeigt TypeError. Suchen Sie daher in der Browserkonsole nach der tatsächlichen Ursache. Node.js erzwingt CORS nicht, daher kann eine Anfrage, die in einem Skript funktioniert, im Browser dennoch fehlschlagen.

Standardmäßig senden Browser bei Cross-Origin-Anfragen keine Cookies. Stellen Sie bei Bedarf credentials: "include" ein und stellen Sie sicher, dass der Server dies zulässt. Fügen Sie niemals geheime API-Schlüssel in Browser-JavaScript ein, da sie jeder lesen kann. Behalten Sie sie auf Ihrem Server.

Häufige Fehler

  • Nicht überprüft response.ok. Fehlerantworten werden als Erfolg behandelt.
  • Das Zweite vergessen await. response.json() gibt auch ein Versprechen zurück.
  • Vergessen JSON.stringify. Ein Objekt weitergeben, während der Körper es sendet [object Object].
  • Setzen von Content-Type mit FormData. Dadurch wird die Grenze überschritten, also lassen Sie es weg.
  • Es gibt keine Zeitüberschreitung. Eine blockierte Anfrage kann dazu führen, dass der Spinner einer Seite auf unbestimmte Zeit läuft.
  • JSON wird auf eine leere Antwort analysiert. A 204 hat keinen Text und json() wird ausgelöst.

Fazit

Das Abrufen ist einfach, wenn Sie sich an die Hauptregel erinnern: Eine Antwort ist nicht dasselbe wie ein Erfolg. Kopieren Sie den kleinen Helfer in Ihr Projekt, fügen Sie ein Timeout hinzu und testen Sie Ihre Fehlerpfade. Erstellen Sie im nächsten Schritt eine kleine Seite, die Daten von einer API lädt, eine klare Fehlermeldung anzeigt und es dem Benutzer ermöglicht, eine langsame Suche abzubrechen.

Häufige Fragen

Löst fetch bei einem 404-Fehler einen Fehler aus?

Nein. fetch lehnt nur ab, wenn keine Antwort empfangen wird, beispielsweise bei einem Netzwerkfehler. Überprüfen Sie bei HTTP-Fehlern „response.ok“ oder „response.status“ selbst.

Wie sende ich JSON mit Fetch?

Setzen Sie die Methode auf POST, fügen Sie einen Content-Type-Header von application/json hinzu und übergeben Sie die Daten als Text über JSON.stringify.

Warum brauche ich beim Abrufen zwei Wartevorgänge?

Der erste wird aufgelöst, sobald die Antwortheader eintreffen. Der zweite wartet darauf, dass der Text heruntergeladen und analysiert wird, was später passieren kann.

Wie stelle ich beim Abruf ein Timeout ein?

Passsignal: AbortSignal.timeout(5000) in den Optionen. Die Anfrage wird dann mit einem TimeoutError abgelehnt, wenn sie länger als so viele Millisekunden dauert.

Ist Fetch in Node.js verfügbar?

Ja. Fetch ist weltweit in Node.js 18 und höher verfügbar. Ältere Versionen benötigen ein Paket, CORS-Regeln gelten jedoch nur in Browsern.

Lerne weiter

Arbeiten Sie mit Stack Quora

Benötigen Sie Hilfe beim Testen, WordPress oder SEO?

Wir helfen Teams, bessere Software zu liefern und ihre Websites zu erweitern. Sagen Sie uns, woran Sie gerade arbeiten, und wir schlagen Ihnen einen klaren nächsten Schritt vor.

Lesen Sie weiter

Weitere Anleitungen finden Sie unter Tests, KI und moderne Entwicklung

Hat Ihnen dieser Artikel gefallen? Wählen Sie ein Thema und springen Sie direkt in unsere neuesten Tutorials.

Künstliche Intelligenz

KI-Halluzinationen erklärt: Warum Sprachmodelle Dinge erfinden und wie man sie reduziert

KI-Halluzinationen erklärt: Was sie sind, warum Sprachmodelle sie produzieren, gängige Typen, wie man sie mit Erdung und Eingabeaufforderungen reduz…

Artikel lesen →
DevOps

Erklärte Umgebungsvariablen: .env-Dateien, Geheimnisse und Konfiguration richtig gemacht

Umgebungsvariablen anhand von Python-Beispielen erklärt, die wir ausgeführt haben: Sie lesen und festlegen, warum jeder Wert ein String ist, .env-Da…

Artikel lesen →
Softwareentwicklung

API-Ratenbegrenzung erklärt: Algorithmen, Header und Behandlung von 429-Fehlern

API-Ratenbegrenzung anhand einer von uns durchgeführten Simulation erklärt: Token-Bucket, festes Fenster, gleitendes Fenster, 429 Antworten, Ratenbe…

Artikel lesen →
Testautomatisierung

Spott in Python: unittest.mock, Patch und die Fehler, die Tests zum Lügen machen

Mocking in Python mit unittest.mock, getestet: Mock und return_value, side_effect, Patchen, wo ein Name verwendet wird, Spezifikation und Autospec, …

Artikel lesen →
Softwaretests

Code-Abdeckung erklärt: Leitungs- und Zweigstellenabdeckung und was 100 % wirklich bedeutet

Erklärung der Codeabdeckung anhand eines echten Coverage.py-Laufs: Zeilen-, Zweig- und Bedingungsabdeckung, Lesen eines Berichts, warum bei 100 % Ab…

Artikel lesen →
Datenbanken & SQL

DELETE vs. TRUNCATE vs. DROP in SQL: Unterschiede, Rollback und Verwendungszweck

DELETE vs. TRUNCATE vs. DROP erklärt mit getestetem SQL: was jeweils entfernt wird, Rollback, Trigger, Identitätsrücksetzung, Geschwindigkeit und wi…

Artikel lesen →
Datenbanken & SQL

Erklärte SQL-Ansichten: Erstellen, nutzen und vermeiden Sie Fallstricke mit Beispielen

SQL-Ansichten anhand der von uns ausgeführten Abfragen erklärt: Erstellen einer Ansicht, Live-Ergebnisse, Ausblenden von Spalten, Leistung, aktualis…

Artikel lesen →
Softwareentwicklung

TypeScript-Schnittstelle vs. Typ: Echte Unterschiede, getestet mit dem Compiler

TypeScript-Schnittstelle vs. Typ, überprüft mit dem echten Compiler: Was beide können, was nur einer kann, Deklarationszusammenführung, Erweiterunge…

Artikel lesen →
Softwareentwicklung

Python *args und **kwargs erklärt: Flexible Funktionen mit klaren Beispielen

Python *args und **kwargs erklärt mit Code, den wir ausgeführt haben: Packen und Entpacken, Parameterreihenfolge, Nur-Schlüsselwort- und Nur-Positio…

Artikel lesen →
Softwareentwicklung

Python-Lambda-Funktionen: Syntax, tatsächliche Verwendung und wann man sie nicht verwendet

Python-Lambda-Funktionen erklärt mit Code, den wir ausgeführt haben: Syntax, Sortierung mit Schlüssel, Karte und Filter, Abschlüsse, die Late-Bindin…

Artikel lesen →
Künstliche Intelligenz

Was sind KI-Agenten? Wie sie funktionieren, mit einer einfachen Agentenschleife, die Sie ausführen können

Was sind KI-Agenten? Eine einfache Anleitung zur Agentenschleife, zu Tools, Speicher und Leitplanken, mit einer kleinen Python-Schleife, die wir aus…

Artikel lesen →
DevOps

Überwachung vs. Beobachtbarkeit: Der wahre Unterschied, mit Protokollen, Metriken und Traces

Überwachung vs. Beobachtbarkeit erklärt: bekannte und unbekannte Fehler, Protokolle, Metriken und Spuren, eine exemplarische Vorgehensweise für Chec…

Artikel lesen →
DevOps

Docker-Volumes vs. Bind Mounts: Containerdaten auf die richtige Art und Weise beibehalten

Docker-Volumes vs. Bind-Mounts erklärt: Warum Containerdaten verschwinden, benannte Volumes, Bind-Mounts, tmpfs, Compose-Beispiele, Backups, Berecht…

Artikel lesen →
Testautomatisierung

TDD vs. BDD: Hauptunterschiede, eine Funktion, die auf beide Arten entwickelt wurde und wann sie jeweils verwendet werden sollte

TDD vs. BDD erklärt mit einer Rabattfunktion, die in beide Richtungen aufgebaut ist: Rot-Grün-Refaktor mit Code, den wir ausgeführt haben, Gegeben-W…

Artikel lesen →
Softwaretests

Benutzerakzeptanztests (UAT): Prozess, Checkliste und reale Beispiele

Benutzerakzeptanztests erklärt: Wer führt ihn durch, wie unterscheidet er sich von der Qualitätssicherung, ein siebenstufiger Prozess, eine UAT-Test…

Artikel lesen →
Datenbanken & SQL

Erklärte SQL-NULL-Werte: IS NULL, COALESCE, NULLIF und die zu vermeidenden Fallen

SQL-NULL-Werte, die mit von uns ausgeführten Abfragen erklärt wurden: dreiwertige Logik, IS NULL, COALESCE, NULLIF, wie Aggregate, Joins und Sortier…

Artikel lesen →
Datenbanken & SQL

SQL CASE WHEN-Anweisung: Syntax, reale Beispiele und häufige Fehler

SQL CASE WHEN anhand der von uns ausgeführten Abfragen erklärt: einfache und durchsuchte Formulare, Bedingungsreihenfolge, Pivots mit SUM, COUNT-Tri…

Artikel lesen →
Softwareentwicklung

Was ist JWT? JSON-Web-Tokens anhand eines funktionierenden Beispiels erklärt

Was ist JWT? JSON Web Tokens erklärt: die drei Teile, ein Token, das in dem von uns ausgeführten Code erstellt und manipuliert wurde, JWT vs. Sitzun…

Artikel lesen →
Softwareentwicklung

Erklärte JavaScript-Ereignisschleife: Aufrufstapel, Mikrotasks und Timer mit Beispielen

Die JavaScript-Ereignisschleife wurde mit dem von uns ausgeführten Code erklärt: Aufrufstapel, Aufgaben- und Mikrotask-Warteschlangen, warum setTime…

Artikel lesen →
Softwareentwicklung

Erklärung von Python-Generatoren und -Ertrag: Sparen Sie Speicher mit echten Beispielen

Python-Generatoren und Yield anhand des von uns ausgeführten Codes erklärt: wie sie angehalten und fortgesetzt werden, gemessene Speichereinsparunge…

Artikel lesen →
Künstliche Intelligenz

Was sind Einbettungen? Vektoren und Kosinusähnlichkeit einfach erklärt

Was sind Einbettungen? Ein Leitfaden in einfacher Sprache zu Vektoren, Kosinusähnlichkeit und semantischer Suche, mit einem kleinen Beispiel, das wi…

Artikel lesen →
DevOps

Blau-Grün vs. Canary-Bereitstellung: Unterschiede, Kompromisse und Auswahl

Blue-Green vs. Canary-Bereitstellung erklärt: Funktionsweise, Kosten, Risiko und Rollback, stabiles Benutzer-Bucketing, das wir getestet haben, Date…

Artikel lesen →
Testautomatisierung

Flaky-Tests: Was sie verursacht und wie man sie endgültig behebt

Flaky-Tests wurden anhand von Demos erklärt, die wir durchgeführt haben: die Hauptursachen, wie man sie bestätigt und diagnostiziert, richtige Korre…

Artikel lesen →
Softwaretests

Lasttest vs. Stresstest: Unterschiede, Metriken und k6-Beispiele

Erläuterungen zu Lasttests und Stresstests: Was die einzelnen Tests beweisen, Spike- und Soak-Tests, welche Kennzahlen wichtig sind, warum Durchschn…

Artikel lesen →
Softwaretests

Testfall vs. Testszenario: Hauptunterschiede, Beispiele und wann man sie jeweils verwendet

Testfall vs. Testszenario erklärt: klare Definitionen, eine Tabelle nebeneinander, eine Funktion zum Zurücksetzen von Passwörtern, die von Szenarios…

Artikel lesen →
Datenbanken & SQL

SQL-Abfrageoptimierung: Ausführungspläne lesen und langsame Abfragen mit Zeitvorgaben beheben

An einer Million Zeilen getestete SQL-Abfrageoptimierung: Ausführungspläne lesen, die richtigen Indizes hinzufügen, nicht sargierbare Filter korrigi…

Artikel lesen →
Datenbanken & SQL

SQL UNION vs. UNION ALL: Unterschiede, Beispiele und getestete Leistung

SQL UNION vs. UNION ALL anhand der von uns ausgeführten Abfragen erklärt: Duplikate, die Regeln, denen beide folgen, ein echter Datenfehler, gemesse…

Artikel lesen →
Softwareentwicklung

Tutorial zur JavaScript-Abruf-API: GET, POST, Fehlerbehandlung und Zeitüberschreitungen

Ein JavaScript-Abruf-API-Tutorial, das auf einem lokalen Server getestet wurde: GET und POST, warum 404 nicht ausgelöst wird, ein wiederverwendbarer…

Artikel lesen →
Softwareentwicklung

Umgang mit Python-Dateien: Lesen, Schreiben, CSV, JSON und Pathlib mit Beispielen

Die Handhabung von Python-Dateien wird anhand des von uns ausgeführten Codes erklärt: Öffnungsmodi, Lesen großer Dateien, CSV, JSON, Pathlib, Binärd…

Artikel lesen →
Softwareentwicklung

Git merge vs rebase: Unterschiede, Beispiele und wann man was nutzt

Git merge vs rebase erklärt mit echter Log-Ausgabe, einer Vergleichstabelle, der goldenen Regel des Rebase und einem sicheren Team-Workflow.

Artikel lesen →
Softwareentwicklung

Python List Comprehension: Syntax, Beispiele und wann man darauf verzichtet

Python List Comprehension erklärt: Syntax, Filter, if-else, verschachtelte Schleifen, gemessene Zeiten und Fälle, in denen eine normale for-Schleife…

Artikel lesen →
Datenbanken & SQL

SQL Joins erklärt mit Beispielen (Inner, Left, Right, Full)

SQL Joins Schritt für Schritt mit Beispieltabellen und Abfragen verstehen: INNER, LEFT, RIGHT, FULL, CROSS und SELF, plus typische Fehler und Perfor…

Artikel lesen →