Traditionaly, initiating file downloads in the browser relied on simple techniques like anchor tags (<a href="document.xlsx">) or direct navigation (window.location.href = 'document.xlsx'). The major limitation of these approaches is the inability to track the download lifecycle—there are no events to confirm when the transfer completes or fails. Modern web APIs, specifically Blob, ArrayBuffer, the Fetch API, and XMLHttpRequest Level 2 (XHR2), empower browsers to handle binary data directly, making asynchronous file downloads fully trackable.
Using the Fetch API
The Fetch API offers a streamlined, Promise-based interface for network requests. Note that it lacks support in Internet Explorer. Additionally, Fetch defaults to omitting cookies; if the target endpoint requires authentication, ensure you configure the credentials option.
When a Fetch request resolves, it returns a Response instance. Beyond checking the request status via status, ok, or statusText, the Response object provides dedicated methods to parse the payload according to its data type:
response.blob(): Resolves to a Blob object representing raw binary data.response.json(): Resolves to a parsed JSON object, bypassing the need forJSON.parse().response.text(): Resolves to a plain text string.response.formData(): Resolves to a FormData object representing key-value pairs.
For file retrieval, invoking response.blob() yields the binary payload. To trigger the actual browser download action from this Blob, we can utilize libraries like FileSaver.js, which exposes a saveAs functon accepting the Blob and an optional filename.
async function retrieveAndSaveDocument(docUrl, outputName) {
try {
const networkResponse = await fetch(docUrl, {
method: 'GET',
credentials: 'include' // Ensure session cookies are transmitted
});
if (!networkResponse.ok) {
throw new Error(`Server responded with status: ${networkResponse.status}`);
}
const binaryData = await networkResponse.blob();
// Trigger browser save dialog using FileSaver
window.saveAs(binaryData, outputName);
} catch (err) {
console.error('File retrieval failed:', err);
}
}
Using XMLHttpRequest Level 2 (XHR2)
For broader compatibility extending back to IE10, XMLHttpRequest Level 2 provides robust binary data handling. Rather than redesigning the original XHR specification, XHR2 introduces crucial extensions, notably the responseType property. By defining responseType before dispatching the request, the browser automatically parses the server output into the specified format. Supported values include "arraybuffer", "blob", "document", "json", and "text".
Once the request concludes, the processed data is accessible via xhr.response. This supersedes the legacy xhr.responseText property, which was restricted to string output and inadequate for binary payloads. Furthermore, XHR2 introduces intuitive event handlers like onload, replacing the cumbersome onreadystatechange logic. Other newly supported events include onprogress, onerror, onabort, onloadstart, onloadend, and ontimeout.
function fetchBinaryFile(resourcePath, targetFilename) {
const request = new XMLHttpRequest();
request.open('GET', resourcePath, true);
request.responseType = 'blob'; // Direct the browser to parse response as Blob
request.onload = function() {
if (request.status === 200 && request.response) {
// Initiate download sequence via FileSaver
window.saveAs(request.response, targetFilename);
}
};
request.onerror = function() {
console.error('Network error encountered during file download.');
};
request.send();
}