TASIOMIND.DEV — OPERATIONAL▸▸▸FULL STACK DEVELOPER @ GWQ SERVICEPLUS AG▸▸▸FOUNDER — K8SGPT.AI▸▸▸OPEN SOURCE: ACTIVE▸▸▸DISTRIBUTED SYSTEMS / KUBERNETES / AI▸▸▸RUST + GO + PYTHON▸▸▸FIELD TESTED / STATUS — NOMINAL▸▸▸LOCATION: EUROPE/BERLIN▸▸▸TASIOMIND.DEV — OPERATIONAL▸▸▸FULL STACK DEVELOPER @ GWQ SERVICEPLUS AG▸▸▸FOUNDER — K8SGPT.AI▸▸▸OPEN SOURCE: ACTIVE▸▸▸DISTRIBUTED SYSTEMS / KUBERNETES / AI▸▸▸RUST + GO + PYTHON▸▸▸FIELD TESTED / STATUS — NOMINAL▸▸▸LOCATION: EUROPE/BERLIN▸▸▸

AJAX: Ein Leitfaden für asynchrone HTTP-Anfragen in JavaScript

November 24, 2016

AJAX (Asynchronous JavaScript and XML) ist eine grundlegende Webentwicklungstechnik, die es einer Webseite ermöglicht, asynchron mit einem Server zu kommunizieren. Anstatt die gesamte Seite bei jeder Interaktion neu zu laden, können Daten im Hintergrund gesendet und empfangen werden, um die Benutzeroberfläche dynamisch zu aktualisieren.

Dieser Ansatz ist die Basis für moderne, interaktive Webanwendungen und bietet entscheidende Vorteile:

  • Verbesserte User Experience (UX): Nahtlose Interaktionen ohne störende Seitenneuladungen.
  • Effiziente Ressourcennutzung: Es werden nur die tatsächlich benötigten Daten übertragen.
  • Echtzeit-Funktionalität: Ermöglicht die Implementierung von Live-Feeds, Chats und Benachrichtigungen.

Obwohl XML historisch namensgebend war, ist JSON heute das dominierende Format für den Datenaustausch.

Grundkonzepte des HTTP-Protokolls

  • Request: Eine Anfrage vom Client an den Server, bestehend aus Methode (GET, POST, etc.), URL, Headern und einem optionalen Body.
  • Response: Eine Antwort vom Server, bestehend aus einem Statuscode, Headern und einem optionalen Body (Payload).
  • Asynchronität: Die Anfrage blockiert nicht den Haupt-Thread des Browsers, sodass die UI responsiv bleibt.

Wichtige HTTP-Statuscodes

  • 200 OK: Anfrage erfolgreich.
  • 201 Created: Ressource erfolgreich erstellt.
  • 204 No Content: Anfrage erfolgreich, aber keine Daten im Body.
  • 400 Bad Request: Fehlerhafte Anfrage vom Client (z.B. ungültige Daten).
  • 401 Unauthorized / 403 Forbidden: Authentifizierung oder Autorisierung fehlgeschlagen.
  • 404 Not Found: Die angeforderte Ressource existiert nicht.
  • 500 Internal Server Error: Ein allgemeiner Fehler auf dem Server.

Evolution der AJAX-Techniken

  1. XMLHttpRequest (Legacy): Die ursprüngliche, ereignisbasierte Browser-API. Funktional, aber umständlich und veraltet.
  2. jQuery $.ajax() (Historisch): Eine populäre Abstraktion, die die Browser-Inkompatibilitäten von XHR vereinfachte.
  3. Fetch API (Moderner Standard): Eine moderne, Promise-basierte Schnittstelle, die in allen aktuellen Browsern verfügbar ist.
  4. async/await (Syntaktischer Zucker): Eine syntaktische Verbesserung für die Arbeit mit Promises, die asynchronen Code lesbarer macht.

Methode 1: XMLHttpRequest (XHR) - Historisch

XHR ist die ursprüngliche Methode zur Durchführung von AJAX-Anfragen. Die Verwendung wird für neue Projekte nicht mehr empfohlen, ist aber für das Verständnis und die Wartung von Altsystemen relevant.

GET-Anfrage

code
const xhr = new XMLHttpRequest();

// Konfiguriert die Anfrage
xhr.open("GET", "https://api.example.com/data");

// Definiert, was bei erfolgreichem Abschluss passiert
xhr.onload = function () {
  if (xhr.status === 200) {
    const data = JSON.parse(xhr.response);
    console.log("Daten erhalten:", data);
  } else {
    console.error("Fehler:", xhr.status, xhr.statusText);
  }
};

// Definiert die Fehlerbehandlung für Netzwerkprobleme
xhr.onerror = function () {
  console.error("Netzwerkfehler aufgetreten.");
};

// Sendet die Anfrage
xhr.send();

POST-Anfrage mit JSON

code
const xhr = new XMLHttpRequest();
xhr.open("POST", "https://api.example.com/users");

// Setzt die notwendigen Header für eine JSON-Anfrage
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer YOUR_TOKEN_HERE");

xhr.onload = function () {
  if (xhr.status === 201) { // 201 Created
    console.log("Benutzer erstellt:", JSON.parse(xhr.response));
  }
};

const payload = { name: "John Doe", email: "john@example.com" };
xhr.send(JSON.stringify(payload));

Upload-Fortschritt

Ein Bereich, in dem XHR nützlich bleibt, ist die Verfolgung des Upload-Fortschritts, da die Fetch API dies nicht nativ unterstützt.

code
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = function (event) {
  if (event.lengthComputable) {
    const percentComplete = (event.loaded / event.total) * 100;
    console.log(`Upload-Fortschritt: ${percentComplete.toFixed(2)}%`);
  }
};

const formData = new FormData();
formData.append("file", myFileInput.files[0]);

xhr.open("POST", "https://api.example.com/upload");
xhr.send(formData);

Methode 2: Fetch API - Moderner Standard

Die Fetch API ist die empfohlene Methode für neue Projekte. Sie ist Promise-basiert und bietet eine saubere, flexible Schnittstelle.

GET-Anfrage mit async/await (Empfohlen)

code
async function fetchData() {
  try {
    const response = await fetch("https://api.example.com/data");

    // Wichtig: fetch() wirft bei HTTP-Fehlern (4xx/5xx) keinen Fehler!
    if (!response.ok) {
      throw new Error(`HTTP-Fehler! Status: ${response.status}`);
    }

    const data = await response.json();
    console.log(data);
    return data;
  } catch (error) {
    console.error("Fehler beim Abrufen der Daten:", error);
  }
}

POST-Anfrage mit JSON

code
async function createUser(payload) {
  try {
    const response = await fetch("https://api.example.com/users", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": "Bearer YOUR_TOKEN_HERE",
      },
      body: JSON.stringify(payload),
    });

    if (!response.ok) {
      throw new Error(`HTTP-Fehler! Status: ${response.status}`);
    }

    return await response.json();
  } catch (error) {
    console.error("Fehler beim Erstellen des Benutzers:", error);
  }
}

Timeout mit AbortController

fetch bietet keinen nativen Timeout. Dieser kann jedoch mit einem AbortController implementiert werden.

code
async function fetchWithTimeout(url, timeout = 5000) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);

  try {
    const response = await fetch(url, { signal: controller.signal });
    return response;
  } finally {
    clearTimeout(timeoutId);
  }
}

CORS (Cross-Origin Resource Sharing)

Aus Sicherheitsgründen erzwingen Browser die Same-Origin Policy, die verhindert, dass eine Webseite Anfragen an eine andere Domain (Origin) stellt. Um Cross-Origin-Anfragen zu ermöglichen, muss der Zielserver CORS unterstützen, indem er den Access-Control-Allow-Origin-Header in seiner Antwort sendet.


Bibliotheken und Frameworks

In React-Anwendungen werden oft spezialisierte Bibliotheken für den Datenabruf verwendet, die über fetch hinausgehen:

  • Axios: Ein beliebter, Promise-basierter HTTP-Client mit Features wie Interceptors und Timeouts.
  • SWR & React Query (TanStack Query): Hoch-abstrahierte Bibliotheken, die Caching, Revalidierung, und Status-Management für Datenabfragen bereitstellen.

Beispiel mit Axios:

code
import axios from "axios";

async function fetchDataWithAxios() {
  try {
    const response = await axios.get("https://api.example.com/data");
    console.log(response.data);
  } catch (error) {
    // Axios wirft automatisch Fehler bei 4xx/5xx Statuscodes
    console.error("Fehler:", error.message);
  }
}

Best Practices

  • Fehlerbehandlung: Implementieren Sie immer eine robuste Fehlerbehandlung, sowohl für Netzwerkprobleme als auch für HTTP-Fehlerstatus.
  • Timeouts: Setzen Sie Timeouts, um zu verhindern, dass Ihre Anwendung auf langsame Serverantworten wartet.
  • Sicherheit: Speichern Sie niemals API-Schlüssel oder andere sensible Daten im Frontend-Code.
  • Validierung: Validieren Sie immer die vom Server empfangenen Daten, bevor Sie sie verwenden.