Nutzung von XMLHttpRequest
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
In diesem Leitfaden betrachten wir, wie man XMLHttpRequest
verwendet, um HTTP-Anfragen zu stellen, um Daten zwischen der Website und einem Server auszutauschen.
Beispiele für sowohl häufige als auch weniger bekannte Anwendungsfälle für XMLHttpRequest
sind enthalten.
Um eine HTTP-Anfrage zu senden:
- Erstellen Sie ein
XMLHttpRequest
-Objekt. - Öffnen Sie eine URL.
- Senden Sie die Anfrage.
Nach Abschluss der Transaktion enthält das XMLHttpRequest
-Objekt nützliche Informationen, wie den Antwortinhalt und den HTTP-Status des Ergebnisses.
function reqListener() {
console.log(this.responseText);
}
const req = new XMLHttpRequest();
req.addEventListener("load", reqListener);
req.open("GET", "http://www.example.org/example.txt");
req.send();
Arten von Anfragen
Eine Anfrage, die über XMLHttpRequest
gestellt wird, kann die Daten auf zwei Arten abrufen, asynchron oder synchron. Die Art der Anfrage wird durch das optionale async
-Argument (das dritte Argument) festgelegt, das in der Methode XMLHttpRequest.open()
gesetzt wird. Wenn dieses Argument true
oder nicht angegeben ist, wird das XMLHttpRequest
asynchron verarbeitet, andernfalls wird der Vorgang synchron behandelt. Eine ausführliche Diskussion und Demonstrationen dieser beiden Arten von Anfragen finden Sie auf der Seite synchronous and asynchronous requests. Sie können keine synchronen Anfragen außerhalb von Web-Workern verwenden, da dies die Hauptschnittstelle einfrieren würde.
Hinweis:
Der Konstruktor XMLHttpRequest
ist nicht nur auf XML-Dokumente beschränkt. Er beginnt mit "XML", weil zur Zeit seiner Erstellung das Hauptformat für den asynchronen Datenaustausch XML war.
Umgang mit Antworten
Es gibt mehrere Arten von Antwortattributen, die für den XMLHttpRequest()
-Konstruktor definiert sind. Diese geben dem Client, der das XMLHttpRequest
durchführt, wichtige Informationen über den Status der Antwort. Einige Fälle, in denen der Umgang mit Nicht-Text-Antworttypen eine gewisse Manipulation und Analyse erfordert, sind in den folgenden Abschnitten beschrieben.
Analyse und Manipulation der responseXML-Eigenschaft
Wenn Sie XMLHttpRequest
verwenden, um den Inhalt eines entfernten XML-Dokuments abzurufen, wird die responseXML
-Eigenschaft ein DOM-Objekt enthalten, das ein geparstes XML-Dokument darstellt. Dies könnte sich als schwierig erweisen, zu manipulieren und zu analysieren. Es gibt vier primäre Wege, dieses XML-Dokument zu analysieren:
- Verwendung von XPath, um Teile davon anzusprechen (oder darauf zu verweisen).
- Manuelles Parse und Serialisieren von XML zu Strings oder Objekten.
- Verwendung von
XMLSerializer
, um DOM-Bäume in Strings oder Dateien zu serialisieren. RegExp
kann verwendet werden, wenn Sie den Inhalt des XML-Dokuments im Voraus kennen. Sie könnten Zeilenumbrüche entfernen wollen, wenn SieRegExp
verwenden, um im Hinblick auf Zeilenumbrüche zu scannen. Diese Methode ist jedoch ein "letzter Ausweg", da sie bei einer geringfügigen Änderung des XML-Codes wahrscheinlich fehlschlagen wird.
Hinweis: XMLHttpRequest
kann jetzt HTML für Sie interpretieren, indem die responseXML
-Eigenschaft verwendet wird. Lesen Sie den Artikel über HTML in XMLHttpRequest, um zu erfahren, wie Sie dies tun.
Verarbeitung einer responseText
-Eigenschaft, die ein HTML-Dokument enthält
Wenn Sie XMLHttpRequest
verwenden, um den Inhalt einer entfernten HTML-Webseite abzurufen, ist die responseText
-Eigenschaft ein String, der das rohe HTML enthält. Dies könnte sich als schwierig erweisen, zu manipulieren und zu analysieren. Es gibt drei primäre Wege, diesen rohen HTML-String zu analysieren und zu parsen:
- Verwenden Sie die
XMLHttpRequest.responseXML
-Eigenschaft, wie im Artikel HTML in XMLHttpRequest behandelt. - Integrieren Sie den Inhalt in den Body eines Dokumentfragments über
fragment.body.innerHTML
und durchlaufen Sie das DOM des Fragments. RegExp
kann verwendet werden, wenn Sie den Inhalt des HTML-responseText
im Voraus kennen. Sie könnten Zeilenumbrüche entfernen wollen, wenn SieRegExp
verwenden, um im Hinblick auf Zeilenumbrüche zu scannen. Diese Methode ist jedoch ein "letzter Ausweg", da sie bei einer geringfügigen Änderung des HTML-Codes wahrscheinlich fehlschlagen wird.
Umgang mit binären Daten
Obwohl XMLHttpRequest
am häufigsten zum Senden und Empfangen von Textdaten verwendet wird, kann es auch zum Senden und Empfangen von Binärinhalten genutzt werden. Es gibt mehrere gut getestete Methoden, um die Antwort eines XMLHttpRequest
zur Übertragung binärer Daten zu zwingen. Diese beinhalten die Verwendung der overrideMimeType()
-Methode auf dem XMLHttpRequest
-Objekt und sind eine praktikable Lösung.
const req = new XMLHttpRequest();
req.open("GET", url);
// retrieve data unprocessed as a binary string
req.overrideMimeType("text/plain; charset=x-user-defined");
/* … */
Es stehen jedoch modernere Techniken zur Verfügung, da das responseType
-Attribut jetzt mehrere zusätzliche Inhaltstypen unterstützt, was das Senden und Empfangen von Binärdaten erheblich erleichtert.
Zum Beispiel betrachten Sie dieses Snippet, das den responseType
von "arraybuffer"
verwendet, um den entfernten Inhalt in ein ArrayBuffer
-Objekt zu laden, das die rohen Binärdaten speichert.
const req = new XMLHttpRequest();
req.onload = (e) => {
const arraybuffer = req.response; // not responseText
/* … */
};
req.open("GET", url);
req.responseType = "arraybuffer";
req.send();
Weitere Beispiele finden Sie auf der Seite Sending and Receiving Binary Data.
Fortschritt überwachen
XMLHttpRequest
bietet die Möglichkeit, auf verschiedene Ereignisse zu hören, die während der Bearbeitung der Anfrage auftreten können. Dies schließt regelmäßige Fortschrittsbenachrichtigungen, Fehlermeldungen und Ähnliches ein.
Die Unterstützung für DOM progress
-Ereignismonitoring von XMLHttpRequest
-Übertragungen folgt der Spezifikation für Fortschrittsereignisse: Diese Ereignisse implementieren das ProgressEvent
-Interface. Die tatsächlichen Ereignisse, die Sie überwachen können, um den Zustand einer laufenden Übertragung zu bestimmen, sind:
progress
-
Die Menge an abgerufenen Daten hat sich geändert.
load
-
Die Übertragung ist abgeschlossen; alle Daten sind jetzt in der
response
.
const req = new XMLHttpRequest();
req.addEventListener("progress", updateProgress);
req.addEventListener("load", transferComplete);
req.addEventListener("error", transferFailed);
req.addEventListener("abort", transferCanceled);
req.open();
// …
// progress on transfers from the server to the client (downloads)
function updateProgress(event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
// …
} else {
// Unable to compute progress information since the total size is unknown
}
}
function transferComplete(evt) {
console.log("The transfer is complete.");
}
function transferFailed(evt) {
console.log("An error occurred while transferring the file.");
}
function transferCanceled(evt) {
console.log("The transfer has been canceled by the user.");
}
Wir fügen Ereignis-Listener für die verschiedenen Ereignisse hinzu, die während der Durchführung einer Datenübertragung mit XMLHttpRequest
gesendet werden.
Hinweis:
Sie müssen die Ereignis-Listener hinzufügen, bevor Sie open()
auf die Anfrage aufrufen. Andernfalls werden die progress
-Ereignisse nicht ausgelöst.
Der Fortschrittsereignis-Handler, der durch die updateProgress()
-Funktion in diesem Beispiel angegeben wird, erhält die Gesamtanzahl der zu übertragenden Bytes sowie die bisher übertragenen Bytes in den Feldern total
und loaded
des Ereignisses. Wenn jedoch das Feld lengthComputable
falsch ist, ist die Gesamtlänge unbekannt und wird null sein.
Fortschrittsereignisse existieren sowohl für Download- als auch für Upload-Übertragungen. Die Download-Ereignisse werden auf dem XMLHttpRequest
-Objekt selbst ausgelöst, wie im obigen Beispiel gezeigt. Die Upload-Ereignisse werden auf dem XMLHttpRequest.upload
-Objekt ausgelöst, wie unten gezeigt:
const req = new XMLHttpRequest();
req.upload.addEventListener("progress", updateProgress);
req.upload.addEventListener("load", transferComplete);
req.upload.addEventListener("error", transferFailed);
req.upload.addEventListener("abort", transferCanceled);
req.open();
Hinweis:
Fortschrittsereignisse sind nicht für das
file:
-Protokoll verfügbar.
Fortschrittsereignisse kommen für jedes Datenstück herein, das empfangen wird, einschließlich des letzten Stücks, in Fällen, in denen das letzte Paket empfangen und die Verbindung geschlossen wird, bevor das Fortschrittsereignis ausgelöst wird. In diesem Fall wird das Fortschrittsereignis automatisch ausgelöst, wenn das Ladeereignis für dieses Paket eintritt. Dadurch können Sie den Fortschritt zuverlässig überwachen, indem Sie nur das "Fortschritt"-Ereignis beobachten.
Man kann auch alle drei Lade-Endbedingungen (abort
, load
oder error
) mit dem loadend
-Ereignis erkennen:
req.addEventListener("loadend", loadEnd);
function loadEnd(e) {
console.log(
"The transfer finished (although we don't know if it succeeded or not).",
);
}
Beachten Sie, dass es keine Möglichkeit gibt, aus den Informationen, die vom loadend
-Ereignis empfangen werden, mit Sicherheit zu erkennen, welche Bedingung den Vorgang beendet hat; Sie können dies jedoch verwenden, um Aufgaben zu bearbeiten, die in allen End-of-Transfer-Szenarien erledigt werden müssen.
Letztes Änderungsdatum abrufen
function getHeaderTime() {
console.log(this.getResponseHeader("Last-Modified")); // A valid GMTString date or null
}
const req = new XMLHttpRequest();
req.open(
"HEAD", // use HEAD when you only need the headers
"your-page.html",
);
req.onload = getHeaderTime;
req.send();
Handeln, wenn sich das letzte Änderungsdatum ändert
Lassen Sie uns zwei Funktionen erstellen:
function getHeaderTime() {
const lastVisit = parseFloat(
window.localStorage.getItem(`lm_${this.filepath}`),
);
const lastModified = Date.parse(this.getResponseHeader("Last-Modified"));
if (isNaN(lastVisit) || lastModified > lastVisit) {
window.localStorage.setItem(`lm_${this.filepath}`, Date.now());
isFinite(lastVisit) && this.callback(lastModified, lastVisit);
}
}
function ifHasChanged(URL, callback) {
const req = new XMLHttpRequest();
req.open("HEAD" /* use HEAD - we only need the headers! */, URL);
req.callback = callback;
req.filepath = URL;
req.onload = getHeaderTime;
req.send();
}
Und um zu testen:
// Let's test the file "your-page.html"
ifHasChanged("your-page.html", function (modified, visit) {
console.log(
`The page '${this.filepath}' has been changed on ${new Date(
nModified,
).toLocaleString()}!`,
);
});
Wenn Sie wissen möchten, ob die aktuelle Seite geändert wurde, lesen Sie den Artikel über document.lastModified
.
Cross-site XMLHttpRequest
Moderne Browser unterstützen Cross-Site-Anfragen durch Implementierung des Cross-Origin Resource Sharing (CORS)-Standards. Solange der Server so konfiguriert ist, dass er Anfragen von der Herkunft Ihrer Webanwendung zulässt, funktioniert XMLHttpRequest
. Andernfalls wird eine INVALID_ACCESS_ERR
-Ausnahme ausgelöst.
Cache umgehen
Ein browserübergreifender Ansatz, um den Cache zu umgehen, besteht darin, einen Zeitstempel an die URL anzuhängen, wobei darauf zu achten ist, dass ein "?" oder "&" gegebenenfalls eingefügt wird. Zum Beispiel:
http://example.com/bar.html -> http://example.com/bar.html?12345 http://example.com/bar.html?foobar=baz -> http://example.com/bar.html?foobar=baz&12345
Da der lokale Cache durch die URL indiziert wird, führt dies dazu, dass jede Anfrage einzigartig ist, wodurch der Cache umgangen wird.
Sie können URLs automatisch mit dem folgenden Code anpassen:
const req = new XMLHttpRequest();
req.open("GET", url + (/\?/.test(url) ? "&" : "?") + new Date().getTime());
req.send(null);
Sicherheit
Der empfohlene Weg, um Cross-Site-Scripting zu ermöglichen, ist die Verwendung des Access-Control-Allow-Origin
-HTTP-Headers in der Antwort auf die XMLHttpRequest.
XMLHttpRequests werden gestoppt
Wenn Sie mit einer XMLHttpRequest abschließen, die status=0
und statusText=null
erhält, bedeutet dies, dass die Anfrage nicht erlaubt war. Sie war UNSENT
. Ein wahrscheinlicher Grund dafür ist, wenn sich der XMLHttpRequest
-Ursprung (bei der Erstellung der XMLHttpRequest) geändert hat, als die XMLHttpRequest anschließend open()
wird. Dies kann beispielsweise passieren, wenn man eine XMLHttpRequest hat, die bei einem onunload
-Ereignis für ein Fenster ausgelöst wird, die erwartete XMLHttpRequest erstellt wird, wenn das zu schließende Fenster noch vorhanden ist und schließlich die Anfrage gesendet wird (mit anderen Worten open()
), wenn dieses Fenster seinen Fokus verliert und ein anderes Fenster den Fokus erhält. Der effektivste Weg, dieses Problem zu vermeiden, besteht darin, einen Listener auf das DOMActivate
-Ereignis des neuen Fensters zu setzen, das ausgelöst wird, sobald das beendete Fenster sein unload
-Ereignis trägt.
Spezifikationen
Specification |
---|
XMLHttpRequest Standard # interface-xmlhttprequest |
Browser-Kompatibilität
BCD tables only load in the browser