Javascript XHR – XMLHttpRequest

Der XMLHttpRequest (kurz XHR) tauscht Daten zwischen Client und Server im Hintergrund aus, ohne die Seite komplett neu zu laden. Diese Technik wurde als Ajax (Asynchronous Javascript And XML) bekannt: Das war der Kern von WEB 2.0.

XMLHttprequest Grundlagen: XML-Datei vom Server lesen

Daten im Hintergrund laden statt Seiten neu laden

Heute ist der XMLHttpRequest eine »Legacy API« – eine Schnittstelle, die nicht weiter entwickelt wird.

Bei den frühen klassischen Webanwendungen (z.B. bei einer Anfrage an ein PHP-Skript) lösten Aktionen des Benutzers einen HTTP-Request zurück zum Server aus.

Kein XHR

Das PHP-Script verifizierte den Benutzer, las Daten aus der Datenbank, berechnete ein paar Zahlen und lieferte dann eine komplett neue HTML-Seite an den Client aus. Dabei bestand die neue Seite zum größten Teil aus denselben Elementen wie vorher und nur wenige Inhalte waren tatsächlich geändert.

XMLHttpRequest (kurz XHR) hingegen prüfte z.B. Formulareingaben im Hintergrund gegen die Datenbank ohne Hin- und Her zwischen Client und der PHP-Anwendungen auf dem Server, und lädt nur zusätzliche Informationen.

XHR – Daten im Hintergrund holen

Das XMLHttpRequest-Objekt enstand 2006 und ist ein eingebautes Objekt des Browsers. Er führte HTTP-Requests ohne ein Refresh der Seite durch.

XMLHttpRequest: Datei vom Server laden

XHR ist eine Schnittstelle zwischen Javascript und den Daten auf dem Server. Im einfachsten Fall holt Javascript Daten aus einer XML- oder JSON-Datei vom Server – ohne Beteiligung einer serverseitigen Anwendung. Der Name XMLHttpRequest ist irreführend, denn der XMLHttpRequest unterstützt nicht nur XML, sondern alle textbasierten Formate, und sowohl Requests als auch Antworten (Response). Alles, was Javascript braucht, um eine JSON-Datei vom Server zu laden, ist ein HTML-Element für die Daten.

<ul id="products"></ul>

Die JSON-Datei enthält ein Array von Objekten, die wiederum die Informationen zu drei Bildern bereitstellen.

[
	{"src": "lampe-01.webp", "width": 531, "height": 509, "alt": "Lampe »Munkola«"},
	{"src": "lampe-02.webp", "width": 531, "height": 509, "alt": "Lampe »Mirmis«"},
	{"src": "lampe-03.webp", "width": 531, "height": 509, "alt": "Lampe »Jolii«"}
]
①   const xhr = new XMLHttpRequest();
②   xhr.open ("GET", "xmlhttp-request.json");

③   xhr.onload = function() {
    	const data = JSON.parse (this.responseText);
    	data.forEach (item => {
    		const li = document.createElement ("li");
    		const img = document.createElement ("img");
    		img.src = `img/${item.src}`;
    		li.append (img);
    		document.querySelector ("#products").append (li);
       });
    }

④   xhr.send();
  1. XMLHTTPRequest initialisieren
  2. Verbindung zum Server aufgebauen
  3. Vorbereitung für den Datenempfang
  4. Request senden, erst jetzt wird ③ xhr.onload ausgeführt.

    fetch oder XMLHttpRequest?

    Wenn keine Rücksicht auf völlig veraltete Browser nötig ist, wird heute fetch anstelle des XMLHttp-Requests verwendet. fetch ist einfacher zu nutzen, flexibler und die Promise-basierte Syntax macht den Code besser lesbar.

    fetch ("booklist.json")
    	.then (response => response.json ())
    	.then (data => console.log (data))
    	.catch (error => console.error ("Fehler:", error));
    

    xhr.send(formData): Datei-Upload mit Progress-Bar

    Auch wenn fetch heute bevorzugt wird, hat der XMLHttpRequest Vorteile: Die Fortschrittskontrolle für Upload (xhr.upload.onprogress) und Downloads (xhr.onprogress) ist sinnvoll, wenn größere Dateien bewegt werden.

    <input type="file" id="fileInput" name="files[]" multiple>
    <progress id="progressBar" value="0" max="100"></progress>
    <button id="btn" type="button">Upload</button>
    <div id="status"></div>
    

    Überträgt das Skript Daten an den Server, ist der erste Parameter von xhr.open ein POST, und der Parameter von xhr.send verweist auf die Daten, die an den Server gesendet werden sollen.

    function uploadFiles() {
    	const files = document.getElementById('fileInput').files;
    	const formData = new FormData();
    
    	for (let i=0; i<files.length; i++) {
    		formData.append('files[]', files[i]);
    	}
    
    	const xhr = new XMLHttpRequest();
    	xhr.open('POST', 'upload.php', true);
    
    	// Fortschrittsanzeige
    	xhr.upload.onprogress = function(event) {
    		if (event.lengthComputable) {
    			const percentComplete = (event.loaded / event.total) * 100;
    			document.getElementById('progressBar').value = percentComplete;
    		}
    	};
    
    	// Erfolgs-/Fehler-Handler
    	xhr.onload = function() {
    		if (xhr.status === 200) {
    			document.getElementById('status').innerText = 'Erfolgreich geladen';
    		} else {
    			document.getElementById('status').innerText = 'Upload fehlgeschlagen!';
    		}
    	};
    
    	// Fehler-Handler
    	xhr.onerror = function() {
    		document.getElementById('status').innerText = 'Netzwerkfehler';
    	};
    
    	xhr.send(formData);
    }
    

    Das Beispiel sendet Daten mit formData als Name-Wert-Paar und kodiert die Daten bei der Übertragung.

    event.lengthComputable ist eine boolesche Eigenschaft und zeigt an, ob eine Ressource eine berechenbare Länge hat.

    Noch den Klick auf den Upload-Button abfangen und die Funktion aufrufen:

    const button = document.querySelector("#btn");
    button.addEventListener ("click", function () {
    	uploadFiles();
    });
    

    XMLHttpRequest timeout

    Falls das Laden die Geduld des Betrachters strapazieren sollte, kann ein timeout-Event nach einer akzeptablen Wartezeit den XMLHttpRequest abbrechen, um Geduld bitten oder ein Warterädchen einspielen.

    Alle modernen Browser, aber nicht IE11 und Vorgänger.

    xhr2.timeout = 2500;
    

    Timeout abfangen und abbrechen oder den Request erneut absenden.

    xhr2.ontimeout = function () {
       message.innerHTML = "Das dauert mal wieder viel zu lang … ";
       // xhr.abort();
       xhr.send();
    }
    
    Suchen auf mediaevent.de