XMLHttpRequest mit JSON, Progress und formData

Der XMLHttpRequest hat seit seinem ersten offiziellen Auftritt neue Methoden, Eigenschaften und Events hinzugewonnen, die das Arbeiten erleichtern und den Code effizienter gestalten. Obwohl fetch meist einfacher als der XMLHttpRequest ist, bietet der XHR Fortschrittskontrolle, Timeout und Abort und versteht sich heute auch mit FormData.

xmlhttp request mit onload anstelle von onreadystatechange

Der moderne XMLHttpRequest

Der XMLHttpRequest hat immer noch seine Vorteile gegenüber fetch: Fortschrittskontrolle mit HTML Progress, einen timeout wenn's zu lang dauert, einfaches Handling von JSON und onload anstelle von onreadystatechanged.

Hinzugekommen sind also

  • timeout
  • FormData
  • Binärdaten auf den Server laden
  • Fortschrittskontrolle bei Uploads
  • Media Type und Kodierung der Antworten

Heute können wir auf die Abfragen nach alten IE-Versionen verzichten. Das macht den XMLHttpRequest schlank und einfache Aufgaben überschaubar.

let xhr = new XMLHttpRequest();

     Request-Methode  URL der Anwendung
            │            │
            ▼            ▼
xhr.open ("GET", "php-backend.php");
xhr.send (null);

Das ist der HTTP-Request an den Server. Der erste Parameter der Methode open gibt die Request-Methode an (GET oder POST), der zweite Parameter die URL zum Anwendung auf dem Server. Die letzte Zeile sendet den Request mit dem Parameter null.

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 onload statt onreadystatechange

Früher wurde beim XMLHTTPRequest die Antwort vom Server unter dem Dauerfeuer von onreadystatechange erwartet. onreadystatechange feuert tatsächlich aus allen Kanonen: Ununterbrochen vom Absenden des Requests bis zur Ankunft der Antwort. onload hingegen feuert nur, wenn der Request erfolgreich heimkehrt.

onload wurde als Event in XMLHttpRequest 2 aufgenommen, während onreadystatechange seit der ersten Spezifikation dabei ist.

XMLHttpRequest responseType="json"

Wird der XHR-Request mit responseType = "json" abgeschickt, liegt die Response fertig geparst als JSON-Objekt vor.

let xhr2 = new XMLHttpRequest();
xhr2.open("GET", "autor.json", true);
xhr2.responseType = "json";
xhr2.send();

Die Abfrage if (e.target.responseType === 'json') wendet sich an Browser, die responseType = "json" unterstützen. Ältere Browser (bis IE10) werden in den else-Zweig geschickt und das Script übernimmt das Parsen des JSON-Strings.

xhr2.onload = function (e) {
   console.log ( this.response );
   let obj;
   if (e.target.responseType === 'json') {
	  obj = xhr2.response;
   } else {
      obj = JSON.parse(e.target.responseText);
   }

   document.querySelector(".result").innerHTML = 
      `<div class="title">${obj.book.title}</div>
		<div class="author">${obj.author}</div>
		<div class="published">${obj.book.published}</div>
		<img src="${obj.book.image}">
		<div class="content">${obj.book.content}</div>`;
};

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