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 ist als Ajax (Asynchronous Javascript And XML) bekannt geworden: Das war der Kern von Web 2.0.

XMLHttprequest Grundlagen: XML-Datei vom Server lesen

Daten im Hintergrund laden statt Seiten neu laden

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 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.

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

XHR – Daten im Hintergrund holen

Das XMLHttpRequest-Objekt ist ein eingebautes Objekt des Browsers und führt 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.

    ② XHR open()

    request.open(method, url, asnc, user, passwword);

    Die beiden erforderlichen Parameter der open()-Methode sind die HTTP-Methode und die URL für die Verbindung.

    • GET ist angebracht, wenn es sich im Wesentlichen um eine einfache Anfrage von Daten handelt,
    • POST wird benutzt, wenn die Länge der ausgesendeten Daten größer als 512 Bytes ist.
    • Die URL kann eine vollständige oder relative URL sein.

    async ist ein boolescher Wert und legt festlegt, ob die Transaktion asynchron oder synchron durchgeführt werden soll.

    • Die Voreinstellung ist true für einen asynchronen Request: Die Ausführung des Skripts wird sofort nach dem Absetzen der send()-Methode fortgesetzt – ohne auf die Antwort zu warten.
    • Wird der Wert auf false gesetzt, »steht« das Skript und wartet, bis der Request gesendet und die Antwort vom Server angekommen ist.

    async="false" gilt heute als »deprecated«, veraltet, da sie vom Benutzer als verwirrend und belastend empfunden wird.

    ④ XHR send()

    Im Workflow des XMLHttpRequest muss zuerst das XMLHttpRequest-Objekt durch open() initialisiert werden. Im nächsten Schritt werden die Request Headers mitsetRequestHeader gesetzt und am Ende wird send() aufgerufen. Die Event Listener sollten registriert sein, bevor send() aufgerufen wird.

    send() sendet einen Request an den Server (bei GET). send(string) sendet einen Request an den Server (bei POST).

    const xml = "<xml><query><autor>Hergé</autor></query></xml>";
    xmlhttp.send(xml);
    
    const xhr = new XMLHttpRequest();
    xhr.open( 'post', 'formdata.php', true );
    
    xhr.onload () {
    }
    
    xhr.send(data);
    

    oder Übertragung von FormData mit Schlüssel-Wertpaaren an

    const form = new FormData();
    form.append("member", "Heinz");
    
    const formXHR = new XMLHttpRequest();
    formXHR.open("POST", "getfile.php");
    formXHR.send(form);
    

    FormData ist nicht auf das Senden von Strings begrenzt, sondern kann auch Files und Blobs versenden.

    ③ XMLHttpRequest.responseText

    Der Zugriff auf die Daten, die der Server zurückliefert, erfolgt über xhr.responseText, xhr.responseXML oder xhr.response.

    responseText
    Antwort als Text
    responseXML
    Objekt wird als vollwertiger XML-Knoten des DOM geparst
    response
    je nachdem, was als responseType gesetzt wurde: ArrayBuffer, Blob, Document, geparst als vollwertiges JavaScript JSON-Objekt oder einfach als String.

    REST-API mit XMLHttpRequest

    Im Grunde genommen funktioniert das Einholen von Informationen aus einer Anwendung auf einer anderen Webseite über ein API (Application Programming Interface) kaum anders als das einfache Lesen einer Datei.

    Viele Anwendungen stellen Programmierschnittstellen zur Verfügung, an denen sie Daten für andere Webseiten oder Anwendungen anbieten. Das Spektrum reicht von Wetterdaten über Straßenkarten (z.B. Openstreetmap auf https://wiki.openstreetmap.org/wiki/API) und den APIs der Social Media bis hin zu Github-Benutzern und -Projekten. Generell bestehen APIs aus Befehlen, Funktionen, Protokollen und Objekten. Jedoch unterscheidet sich die Form von Anbieter zu Anbieter: Ein API ist kein Heimspiel wie die JSON-Datei auf dem eigenen Webspace.

    openthesaurus.de ist ein Projekt im Internet, mit dem Autoren nach Synonymen und Assoziationen für einen Begriff suchen können. Das API von openthesaurus.de bietet wahlweise XML- oder JSON als Austauschformat.

      <input id="thesaurus" value="Türöffner" type="text" placeholder="Gib mir ein Wort!"/>
      <button id="btn">Suche</button>
      <ul id="alt"></ul>
      

      Die Variable word enthält den Begriff, für den ein Ersatz gesucht wird.

      const button = document.querySelector ("#btn");
      const xhr = new XMLHttpRequest ();
      
      button.addEventListener ("click", function () {
      	const xhr = new XMLHttpRequest ();
      	const thesaurus = document.querySelector ("#thesaurus");
      	const word = encodeURI(thesaurus.value);
      	const url = `https://www.openthesaurus.de/synonyme/search?q=${word}&format=application/json`;
      	xhr.open ("GET", url);
      	xhr.onreadystatechange = function () {
      		if (this.readyState === 4 && this.status === 200) {
      			const data = JSON.parse (this.responseText);
      			console.log (data);
      			resolve (data);
      		}
      	}
      	xhr.send ();
      });
      

      Die Ausgabe der JSON-Daten in der Konsole des Browsers zeigt die Struktur der gewünschten Informationen. Die Struktur der Daten eines APIs ist immer wieder eine andere und muss aufgeschlüsselt werden.

      
      ▼ synsets: Array (2)
        ▶ 0 {id: 37879, categories: [], terms: [{term: "ein Anfang (sein)"}, … ]}
        ▶ 1 {id: 43686, categories: [], terms: [{term: "Türen öffnen"}, … ]}
      
      

      Die Funktion resolve löst die gelieferten Objekte auf und überträgt sie in die Liste.

      function resolve (data) {
      	data.synsets.forEach (item => {
      		item.terms.forEach (
      			e => {
      				const li = document.createElement ("li");
      				li.innerHTML = e.term;
      				document.querySelector ("#alt").append (li)
      			}
      		)
      	});
      }
      

      fetch oder XMLHttpRequest?

      Wenn keine Rücksicht auf völlig veraltete Browser nötig ist, wird heute eher fetch als der XMLHttp-Request 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));
      

      IE11 Unterstützung XHR ? XHR open() und send()

      Wenn IE11 noch unter den Hut gebracht werden muss, geht die Zeitreise zurück in die Vergangenheit. Die gebräuchlichste Anweisungssequenz für einen XMLHttpRequest bestand früher aus

      1. dem Erzeugen einer Instanz des XMLHttpRequest-Objekts let xhr = new XMLHttpRequest(),
      2. Aufruf der open()-Methode,
      3. Abfragen von onreadystatechange und Aufruf einer Funktion, die beim Eintreffen der Antwort die Verarbeitung übernimmt.
      4. Senden des Requests mit der send()-Methode
      const xhr = new XMLHttpRequest();
      
      //         Methode  Datei       asynchron
      const.open ( "GET",  "books.xml", true );
      
      xhr.onreadystatechange = function () {
          if (xhr.readyState == 4 && xhr.status == 200) {
              //console.log (xhr.responseText);
              document.querySelector(".listxmp").innerHTML = xhr.responseText;
          }
      }
      
      xhr.send ();
      

      xmlObj.open sendet den GET-Request (nur Daten holen) an den Server. Für die Verarbeitung von Formulardaten wird POST benutzt. Dann wäre der erste Parameter von xhr.open ein POST, und der Parameter von xhr.send wären die Daten, die an den Server gesendet würden.

      Der dritte Parameter steht für async = true. Der Request wird asynchron (quasi nebenher) ausgeführt und blockiert die Seite nicht.

      Wann liegt die Antwort auf den Request vor? xhr.onreadystatechange muss vor dem Senden des Requests mit xhr.send() aufgerufen werden.

      onreadystatechange gibt den Ablauf der Abfrage zurück und durchläuft die Werte 0 bis 4. onreadystatechange feuert bis zur Antwort "4" ununterbrochen den Status der Abfrage. Heute können wir anstelle von xhr.onreadystatechange xhr.onload nutzen. onload meldet sich nur, wenn der Request erfolgreich durchgeführt wurde.

      xhr.responseText ist ein XMLHttpRequest-Objekt, dessen Methoden alle Operationen steuern und dessen Eigenschaften die Daten speichern, die der Server zurückgeliefert.

      readystatechange ist das Event, dass alle Antworten abfängt. Ursprünglich war readystatechange das einzige Ereignis des XMLHttpRequest, aber mit XMLHttpRequest Version 2 sind weitere Events wie XHR onload und onerror hinzugekommen.

      Suchen auf mediaevent.de