W3docs

XMLHttpRequest

XMLHttpRequest (XHR) in JavaScript: open und send, readyState, load/error/timeout-Events, JSON parsen, POST-Daten, Anfragen abbrechen und Vergleich mit der Fetch API.

JavaScript ist eine unverzichtbare Programmiersprache für die Webentwicklung, die dynamische und interaktive Benutzererlebnisse ermöglicht. Eine der wichtigsten Funktionen von JavaScript ist die Fähigkeit, mit Servern zu kommunizieren, Daten abzurufen und Webseiten asynchron zu aktualisieren. Dies wird hauptsächlich durch den Einsatz von XMLHttpRequest (XHR) erreicht. Dieser Artikel bietet einen tiefen Einblick in XMLHttpRequest, einschließlich seiner Methoden, Eigenschaften und praktischen Anwendungen, mit mehreren Codebeispielen zur Unterstützung des Lernens.

Info

XMLHttpRequest arbeitet mit Callback-Funktionen. Für neuen Code greift man üblicherweise zur Fetch API, die auf Promises basiert und sauber mit async/await zusammenarbeitet. XHR lohnt sich dennoch zu verstehen: Man begegnet ihm in älteren Codebasen, und es ist die einzige eingebaute API, die detaillierte Upload-Fortschrittsberichte liefert.

Diese Seite behandelt, was ein XHR-Objekt ist, wie man eine Anfrage mit open und send konfiguriert und sendet, wie man die Antwort über readyState und die load/error/timeout-Events liest, wie man JSON parst, wie man Daten per POST sendet, wie man eine Anfrage abbricht und wie XHR im Vergleich zu fetch abschneidet.

XMLHttpRequest verstehen

XMLHttpRequest (XHR) ist ein eingebautes Browser-Objekt, das JavaScript ermöglicht, eine HTTP- oder HTTPS-Anfrage an einen Server zu senden und die Antwort zu empfangen, ohne die Seite neu zu laden. Das „XML" im Namen ist historisch bedingt – XHR kann jedes Text- oder Binärformat übertragen, und JSON ist heute bei weitem das gebräuchlichste. Diese Fähigkeit, im Hintergrund mit einem Server zu kommunizieren, bildet die Grundlage dessen, was früher als AJAX (Asynchronous JavaScript and XML) bezeichnet wurde.

Der Lebenszyklus einer Anfrage ist immer gleich: Objekt erstellen, es öffnen (Methode und URL konfigurieren), Event-Handler anhängen, um auf das Ergebnis zu reagieren, und es dann senden.

Ein XMLHttpRequest-Objekt erstellen

Zunächst wird eine Instanz erstellt:

const xhr = new XMLHttpRequest();

Eine einzelne XMLHttpRequest-Instanz verwaltet eine Anfrage. Um eine zweite Anfrage zu stellen, muss ein neues Objekt erstellt werden.

Eine HTTP-Anfrage stellen

Sobald das Objekt existiert, wird es mit open konfiguriert und anschließend mit send abgeschickt.

Die open-Methode

open initialisiert eine Anfrage, sendet sie aber noch nicht ab. Sie nimmt mehrere Parameter entgegen:

xhr.open(method, url, async, user, password);
  • method: Die zu verwendende HTTP-Methode, z. B. 'GET' oder 'POST'.
  • url: Die URL, an die die Anfrage gesendet wird.
  • async: Ein boolean, der angibt, ob die Anfrage asynchron ist. Standardmäßig true, und man sollte es fast immer so belassen (siehe Warnung unten).
  • user: Optionaler Benutzername für die HTTP-Authentifizierung.
  • password: Optionales Passwort für die HTTP-Authentifizierung.

Beispiel:

xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
Warnung

Synchrone Anfragen (xhr.open(method, url, false)) frieren die Seite ein, bis die Antwort eintrifft, und sind im Haupt-Thread veraltet. async sollte immer auf true gesetzt bleiben.

Die send-Methode

send sendet die Anfrage an den Server. Alle Event-Handler müssen vor dem Aufruf angehängt werden. Bei einer GET-Anfrage wird sie ohne Argumente aufgerufen. Bei einem POST wird der Anfrage-Body als Argument übergeben.

Beispiel einer GET-Anfrage:

xhr.send();

Beispiel einer POST-Anfrage mit form-kodierten Daten:

xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('param1=value1&param2=value2');

Die Methode setRequestHeader fügt der ausgehenden Anfrage einen HTTP-Header hinzu und muss nach open, aber vor send aufgerufen werden.

Server-Antworten verarbeiten

Zur Verarbeitung von Server-Antworten können verschiedene Event-Listener verwendet werden.

Das onreadystatechange-Event

Das onreadystatechange-Event wird immer dann ausgelöst, wenn sich die readyState-Eigenschaft ändert. Die readyState-Eigenschaft enthält den Status des XMLHttpRequest.

  • 0: UNSENT
  • 1: OPENED
  • 2: HEADERS_RECEIVED
  • 3: LOADING
  • 4: DONE

Eine Anfrage ist nur dann abgeschlossen und erfolgreich, wenn readyState den Wert 4 (DONE) hat und der HTTP-status im Erfolgsbereich liegt (typischerweise 200). Nur auf readyState === 4 zu prüfen ist ein häufiger Fehler, da der Server mit 404 oder 500 geantwortet haben könnte.

Beispiel:

javascript— editable
Hinweis

Obwohl onreadystatechange funktioniert, bevorzugt moderner Code im Allgemeinen onload und onerror für eine einfachere und besser lesbare Anfragenverarbeitung. onreadystatechange wird hauptsächlich verwendet, wenn Zwischenzustände verfolgt werden müssen (wie Fortschritt oder empfangene Header).

Das load-Event

Das load-Event wird ausgelöst, sobald die Antwort vollständig eingegangen ist. Es ist einfacher als onreadystatechange, da man readyState nicht selbst prüfen muss – es wird nur in der DONE-Phase ausgelöst. Man prüft weiterhin status, um einen echten Erfolg von einem HTTP-Fehler zu unterscheiden.

Beispiel:

javascript— editable

Das progress-Event

Bei großen Downloads kann der Fortschritt mit dem progress-Event gemeldet werden. Wenn der Server einen Content-Length-Header sendet, ist das Event determiniert (lengthComputable ist true) und ein Prozentsatz kann berechnet werden:

xhr.onprogress = function(event) {
  if (event.lengthComputable) {
    const percent = Math.round((event.loaded / event.total) * 100);
    console.log(`Downloaded ${percent}%`);
  }
};

Um stattdessen einen Upload zu verfolgen, werden Handler an xhr.upload angehängt (xhr.upload.onprogress). Das Upload-Fortschrittsobjekt ist die eine Funktion, die Fetch noch nicht vollständig replizieren kann.

Fehlerbehandlung

Robuster Code muss Fehler behandeln. Zwei Events decken die Fehlerfälle ab:

  • onerror wird bei einem Fehler auf Netzwerkebene ausgelöst – die Anfrage hat den Server nie erreicht, DNS ist fehlgeschlagen, CORS hat sie blockiert usw. Beachte, dass ein HTTP-404 oder 500 kein Netzwerkfehler ist: Er löst load aus, nicht error – daher muss status weiterhin geprüft werden.
  • ontimeout wird ausgelöst, wenn die Anfrage länger als xhr.timeout Millisekunden dauert. Ein Timeout von 0 (der Standard) bedeutet kein Limit.

Beispiel:

javascript— editable

JSON-Antworten parsen

Server-Antworten sind meistens JSON. Der einfachste Ansatz ist, den Rohtext aus xhr.responseText zu lesen und ihn selbst mit JSON.parse zu parsen:

javascript— editable

Alternativ kann xhr.responseType = 'json' vor dem Senden gesetzt werden, und der Browser parst den Body automatisch. Der geparste Wert ist dann über xhr.response verfügbar (nicht xhr.responseText):

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.responseType = 'json';

xhr.onload = function() {
  if (xhr.status === 200) {
    console.log('title: ' + xhr.response.title); // already an object
  }
};

xhr.send();

responseType akzeptiert auch 'text', 'blob', 'arraybuffer' und 'document' für Nicht-JSON-Nutzdaten.

Daten mit POST senden

Um einen JSON-Body zu senden, wird der Content-Type-Header gesetzt und das Objekt mit JSON.stringify serialisiert:

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.setRequestHeader('Content-Type', 'application/json');

xhr.onload = function() {
  if (xhr.status === 201) { // 201 Created
    console.log('Created:', xhr.responseText);
  }
};

xhr.send(JSON.stringify({ title: 'foo', body: 'bar', userId: 1 }));

Für herkömmliche Formularübermittlungen wird stattdessen ein FormData-Objekt gesendet – der Browser setzt den korrekten Multipart-Content-Type automatisch, daher sollte setRequestHeader dafür nicht aufgerufen werden.

Eine Anfrage abbrechen

xhr.abort() abbricht eine laufende Anfrage, zum Beispiel wenn der Benutzer die Seite verlässt oder eine neue Suchanfrage eingibt. Nach dem Abbruch wird das abort-Event anstelle von load ausgelöst:

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.onabort = () => console.log('Request was cancelled');
xhr.send();

// Later, cancel it:
xhr.abort();

Das Fetch-Äquivalent verwendet einen AbortController.

XMLHttpRequest vs. Fetch

XMLHttpRequestFetch
ProgrammiermodellCallbacks / EventsPromises, funktioniert mit await
Upload-FortschrittJa (xhr.upload)Nein
Download-FortschrittJa (progress-Event)Über Streams (mehr Code)
Abbrechenxhr.abort()AbortController
Fehler bei HTTP-FehlerNein, status wird geprüftNein, response.ok wird geprüft

Für die meisten neuen Projekte ist Fetch die bessere Wahl. Auf XHR sollte man zurückgreifen, wenn detaillierte Upload-Fortschrittsberichte benötigt werden oder eine sehr alte Umgebung unterstützt werden muss.

Fazit

XMLHttpRequest ermöglicht es JavaScript, im Hintergrund Daten mit einem Server auszutauschen: Man erstellt das Objekt, opent es, hängt load/error/timeout-Handler an und sendet es. Wichtig ist, sowohl readyState als auch status zu prüfen, JSON selbst oder über responseType zu parsen und abort() zu verwenden, um veraltete Anfragen abzubrechen. Für die meisten neuen Projekte ist die promise-basierte Fetch API die bessere Wahl, aber das Verständnis von XHR hält einen in älteren Codebasen und in Szenarien wie dem Upload-Fortschritt, wo XHR noch immer überlegen ist, handlungsfähig.

Übungen

Übung
Welche der folgenden Aussagen über XMLHttpRequest sind korrekt?
Welche der folgenden Aussagen über XMLHttpRequest sind korrekt?
Was this page helpful?