XMLHttpRequest Older Way of Handling HTTP Requests
This guide introduces you to XMLHttpRequest, the older way of handling HTTP requests in JavaScript. You will learn how to create and use XMLHttpRequest, send different types of requests, handle responses, and manage security considerations.
Introduction to XMLHttpRequest
What is XMLHttpRequest?
XMLHttpRequest, often abbreviated as XHR, is a built-in browser object that allows you to interact with servers. It can send HTTP or HTTPS requests to a server asynchronously, and it allows you to handle responses from the server without reloading the page. XHR is a cornerstone of AJAX (Asynchronous JavaScript and XML), a technique used to create dynamic and interactive web applications.
Why Use XMLHttpRequest?
Before the introduction of Fetch API and modern web technologies, XMLHttpRequest was the primary method to perform AJAX operations. Understanding XHR is important because it helps you grasp the fundamentals of web communication, client-server interactions, and asynchronous programming.
Basic Usage Example
Let's start with a simple example of using XMLHttpRequest to fetch data from a server.
// Create a new XMLHttpRequest object
var xhr = new XMLHttpRequest();
// Configure it: GET-request for the URL /info
xhr.open('GET', '/info', true);
// Set up a function to handle the response
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) { // check if the request was successful
console.log('Response:', xhr.responseText); // responseText is the server response as a string
} else {
console.error('Error:', xhr.statusText); // statusText holds a text message corresponding to the status code
}
};
// Send the request
xhr.send();
In this example, we create an XHR object, configure it to make a GET request to the server, set up an event handler to handle the response, and finally, send the request.
Setting Up the XMLHttpRequest Object
Creating XMLHttpRequest Instance
To use XMLHttpRequest, you first need to create an instance of it.
var xhr = new XMLHttpRequest();
This line of code initializes a new XHR object that you can use to send requests to the server.
Opening a Request
The open
method initializes a request. It takes three main parameters: the request method, the URL, and a boolean indicating whether the request should be asynchronous.
xhr.open('GET', '/info', true);
- GET: This is the HTTP method. GET is used to request data from a server.
- /info: This is the URL from which you want to fetch data.
- true: This boolean parameter specifies that the request should be asynchronous.
HTTP Methods (GET, POST, PUT, DELETE)
- GET: Requests data from a specified resource.
- POST: Submits data to be processed to a specified resource.
- PUT: Replaces all current representations of the target resource with the uploaded content.
- DELETE: Removes a specific resource.
URL Parameter
The URL parameter specifies the location of the server or resource you want to access.
Asynchronous Parameter
The boolean parameter true
makes the request asynchronous. If set to false
, the request is synchronous, meaning the code execution will pause until the server responds, which is generally not recommended for a smooth user experience.
Sending a Request
GET Requests
GET requests are used to retrieve data from a server.
Example of a GET Request
Let's fetch some JSON data from a public API.
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('Data:', JSON.parse(xhr.responseText));
} else {
console.error('Error:', xhr.statusText);
}
};
xhr.send();
In this example, we send a GET request to a public API and log the JSON response to the console.
POST Requests
POST requests are used to send data to a server.
Setting Request Headers
Before sending a POST request, you often need to set the Content-Type
header.
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
Sending Data with POST Requests
You can send data with POST requests using the send
method.
Example of a POST Request
Let's send some data to a server using a POST request.
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://jsonplaceholder.typicode.com/posts', true);
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('Data:', JSON.parse(xhr.responseText));
} else {
console.error('Error:', xhr.statusText);
}
};
xhr.send(JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
}));
In this example, we send a POST request to a public API with a JSON object and log the response.
Handling Responses
Receiving the Response
The response from the server can be accessed through the responseText
or response
property of the XHR object.
Response Properties
- responseText: Contains the response data as a string.
- responseType: Lets you specify the expected response type (e.g., text, arraybuffer, blob, document, json).
Status Codes
The server responds with a status code that indicates the result of the request.
Checking Response Status
You can check the response status to determine if the request was successful.
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('Success:', xhr.responseText);
} else {
console.error('Error:', xhr.statusText);
}
};
Handling Success
If the request was successful, you can handle the response as needed.
Handling Errors
If the request failed, you can handle the error appropriately.
Ready State Change
Understanding readyState
The readyState
property describes the current status of the request and its response. It has five possible values:
- 0: UNSENT - The request has been set up, but not yet sent.
- 1: OPENED - The
open
method has been called. At this point, the request is ready to be sent but has not been sent yet. - 2: HEADERS_RECEIVED - The
send
method has been called, and the response headers and status are available. - 3: LOADING - The response body is being downloaded. The
responseText
property contains the partial data. - 4: DONE - The request is complete, and the response is ready to be accessed.
Handling readyState Changes
You can handle changes in the readyState
using the onreadystatechange
event handler.
Example of readyState Handling
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) { // Check if the request is complete
if (xhr.status >= 200 && xhr.status < 300) { // Check if the request was successful
console.log('Data:', JSON.parse(xhr.responseText));
} else {
console.error('Error:', xhr.statusText);
}
}
};
xhr.send();
In this example, we handle the readyState
change to determine when the request is complete and whether it was successful.
Aborting a Request
Using abort()
The abort()
method can be used to cancel a request.
Example of Aborting a Request
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('Data:', JSON.parse(xhr.responseText));
} else {
console.error('Error:', xhr.statusText);
}
};
xhr.onerror = function() {
console.error('Network Error');
};
xhr.send();
// Abort the request after 5 seconds
setTimeout(function() {
xhr.abort();
}, 5000);
In this example, we send a request and abort it after 5 seconds using the setTimeout
function.
Cross-Origin Requests
Understanding Cross-Origin Resource Sharing (CORS)
CORS is a security feature implemented by web browsers that allows a server to specify which domain(s) can access its resources.
Setting up CORS on the Server
To allow cross-origin requests, the server must include specific headers in its response.
Handling preflight Requests
When making "complex" requests, the browser performs a preflight request to determine if the server allows the request.
Example of CORS with XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://example.com/data', true);
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('Data:', JSON.parse(xhr.responseText));
} else {
console.error('Error:', xhr.statusText);
}
};
xhr.onerror = function() {
console.error('Network Error');
};
xhr.send(JSON.stringify({
name: 'John',
age: 30
}));
In this example, we send a POST request to a different domain, demonstrating how CORS works in practice.
XMLHttpRequest Event Handlers
Event Types
XHR objects can trigger various events. Here are some of the most common:
onload
Triggered when the request is complete and successful.
onerror
Triggered when the request encounters a network error.
onabort
Triggered when the request is aborted with the abort()
method.
onreadystatechange
Triggered every time the readyState
changes.
onprogress
Triggered periodically to report the progress of the request.
Adding Event Handlers
You can attach event handlers using both inline methods and addEventListener
.
Inline Event Handlers
xhr.onload = function() {
console.log('Request completed successfully');
};
Using addEventListener
xhr.addEventListener('load', function() {
console.log('Request completed successfully');
});
Example of Adding Event Handlers
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onload = function() {
console.log('Data:', JSON.parse(xhr.responseText));
};
xhr.onerror = function() {
console.error('Request failed');
};
xhr.onprogress = function(event) {
console.log('Progress:', event.loaded, '/', event.total);
};
xhr.send();
In this example, we set up multiple event handlers to handle different events triggered by the XHR object.
Modifying Request Headers
Understanding Request Headers
Headers provide additional information about the request or response. You can set request headers using the setRequestHeader
method.
Setting Request Headers
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.setRequestHeader('Authorization', 'Bearer your_access_token_here');
Common Headers
- Content-Type: Specifies the media type of the resource.
- Authorization: Provides credentials for HTTP authentication.
Accessing Response Headers
You can access response headers using the getAllResponseHeaders
and getResponseHeader
methods.
getAllResponseHeaders()
xhr.onload = function() {
console.log(xhr.getAllResponseHeaders()); // Logs all response headers
};
getResponseHeader(headerName)
xhr.onload = function() {
console.log(xhr.getResponseHeader('Content-Type')); // Logs the Content-Type header
};
Example of Modifying Headers
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('Data:', JSON.parse(xhr.responseText));
} else {
console.error('Error:', xhr.statusText);
}
};
xhr.send();
In this example, we set the Content-Type
header and handle the response.
Uploading Files with XMLHttpRequest
File Input
To upload files, you often use an HTML file input element.
FormData Object
The FormData
API provides a way to easily construct sets of key/value pairs to represent form fields and their values.
Example of File Upload
<input type="file" id="fileInput">
<button id="uploadButton">Upload</button>
<script>
document.getElementById('uploadButton').addEventListener('click', function() {
var fileInput = document.getElementById('fileInput');
var file = fileInput.files[0];
var formData = new FormData();
formData.append('file', file);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('Upload successful:', xhr.responseText);
} else {
console.error('Error:', xhr.statusText);
}
};
xhr.onerror = function() {
console.error('Network Error');
};
xhr.send(formData);
});
</script>
In this example, we use an HTML file input to select a file, create a FormData
object, and send it using a POST request.
Security Considerations
Potential Security Vulnerabilities
- Cross-Site Scripting (XSS): Attacker-injected scripts manipulate web pages.
- Cross-Site Request Forgery (CSRF): Attacker forces a victim to perform unwanted actions.
Security Best Practices
- Sanitizing Inputs: Always sanitize input data to prevent XSS attacks.
- Using CORS Properly: Configure CORS to allow only trusted domains.
Example of Secure XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log('Data:', JSON.parse(xhr.responseText));
} else {
console.error('Error:', xhr.statusText);
}
};
xhr.onerror = function() {
console.error('Network Error');
};
xhr.send();
In this example, we send a secure GET request to a server.
Comparing XMLHttpRequest and Fetch API
Key Differences
- Simplified Syntax: Fetch API has a more modern, promise-based syntax.
- Promises-based: Fetch API uses promises, making it easier to work with asynchronous code.
- Methods and Options: Fetch API supports more options for configuring requests.
- Legacy Support: XHR is supported in all browsers, including older versions of Internet Explorer.
When to Use XMLHttpRequest
Use XMLHttpRequest when you need to support very old browsers or when you want finer control over your requests.
Summary and Next Steps
Recap of Key Points
- XMLHttpRequest is a built-in browser object for making HTTP requests.
- You can set various request headers and handle different response types.
- Properly handle CORS and security considerations to protect your application.
- Fetch API is the modern alternative to XHR, offering a more modern and promise-based approach.
Moving Forward with Asynchronous JavaScript
Now that you understand the basics of XMLHttpRequest, you can explore more advanced topics such as the Fetch API, which provides a more modern approach to handling HTTP requests. Learning JavaScript and its capabilities for asynchronous operations will greatly enhance your ability to build dynamic and interactive web applications.
By understanding and mastering XMLHttpRequest, you will have a solid foundation for client-server communication in JavaScript, enabling you to create richer web applications.