XMLHttpRequest is a built-in browser object that allows to make HTTP requests in JavaScript.
Despite of having the word “XML” in its name, it can operate on any data, not only in XML format. We can upload/download files, track progress and much more.
Right now, there’s another, more modern method fetch, that somewhat deprecates XMLHttpRequest.
In modern web-development XMLHttpRequest is used for three reasons:
- Historical reasons: we need to support existing scripts with
XMLHttpRequest. - We need to support old browsers, and don’t want polyfills (e.g. to keep scripts tiny).
- We need something that
fetchcan’t do yet, e.g. to track upload progress.
Does that sound familiar? If yes, then all right, go on with XMLHttpRequest. Otherwise, please head on to Fetch.
The basics
XMLHttpRequest has two modes of operation: synchronous and asynchronous.
Let’s see the asynchronous first, as it’s used in the majority of cases.
To do the request, we need 3 steps:
-
Create
XMLHttpRequest:let xhr = new XMLHttpRequest();The constructor has no arguments.
-
Initialize it, usually right after
new XMLHttpRequest:xhr.open(method, URL, [async, user, password])This method specifies the main parameters of the request:
method– HTTP-method. Usually"GET"or"POST".URL– the URL to request, a string, can be URL object.async– if explicitly set tofalse, then the request is synchronous, we’ll cover that a bit later.user,password– login and password for basic HTTP auth (if required).
Please note that
opencall, contrary to its name, does not open the connection. It only configures the request, but the network activity only starts with the call ofsend. -
Send it out.
xhr.send([body])This method opens the connection and sends the request to server. The optional
bodyparameter contains the request body.Some request methods like
GETdo not have a body. And some of them likePOSTusebodyto send the data to the server. We’ll see examples of that later. -
Listen to
xhrevents for response.These three events are the most widely used:
load– when the request is complete (even if HTTP status is like 400 or 500), and the response is fully downloaded.error– when the request couldn’t be made, e.g. network down or invalid URL.progress– triggers periodically while the response is being downloaded, reports how much has been downloaded.
xhr.onload = function() { alert(`Loaded: ${xhr.status} ${xhr.response}`); }; xhr.onerror = function() { // only triggers if the request couldn't be made at all alert(`Network Error`); }; xhr.onprogress = function(event) { // triggers periodically // event.loaded - how many bytes downloaded // event.lengthComputable = true if the server sent Content-Length header // event.total - total number of bytes (if lengthComputable) alert(`Received ${event.loaded} of ${event.total}`); };
Here’s a full example. The code below loads the URL at /article/xmlhttprequest/example/load from the server and prints the progress:
// 1. Create a new XMLHttpRequest object
let xhr = new XMLHttpRequest();
// 2. Configure it: GET-request for the URL /article/.../load
xhr.open('GET', '/article/xmlhttprequest/example/load');
// 3. Send the request over the network
xhr.send();
// 4. This will be called after the response is received
xhr.onload = function() {
if (xhr.status != 200) { // analyze HTTP status of the response
alert(`Error ${xhr.status}: ${xhr.statusText}`); // e.g. 404: Not Found
} else { // show the result
alert(`Done, got ${xhr.response.length} bytes`); // response is the server response
}
};
xhr.onprogress = function(event) {
if (event.lengthComputable) {
alert(`Received ${event.loaded} of ${event.total} bytes`);
} else {
alert(`Received ${event.loaded} bytes`); // no Content-Length
}
};
xhr.onerror = function() {
alert("Request failed");
};
Once the server has responded, we can receive the result in the following xhr properties:
status- HTTP status code (a number):
200,404,403