Thought leadership from the most innovative tech companies, all in one place.

5 Ways to Download Front-end Files

1. a label, 2. window.open, 3. location.href, 4. location.? Other properties, and 5. XMLHttpRequest. What are the pros and cons of each method?

image

The file download involved in the front-end still has many application scenarios, so how many ways are there for the front-end file download? What are the advantages and disadvantages of each method? Let’s introduce them one by one.

1. a label

File download is achieved through the download attribute of the a tag. This method is the simplest and the most commonly used method. Let’s first look at the sample code:

<a href="[http://www.](http://www.baidu.com)google.com" download="google.html">download</a>

In the above example, we clicked download and found that we jumped to the homepage of Google, and did not actually download the file.
Because a tag download can only download files of the same origin, if it is a cross-domain file, including pictures, audio and video and other media files, it is a preview and cannot be downloaded.
The above code is to achieve file download directly by writing a tag, we can also achieve it through js, the code is as follows:

const a = document.createElement('a')
a.href = '[http://www.google.com'](http://www.baidu.com')
a.download = 'google.html'
a.click()

The effect is the same as the above, it jumps to Baidu’s homepage without downloading files.
The focus here is the download attribute of a tag, which is new in HTML5.
Its function is to specify the downloaded file name. If it is not specified, the downloaded file name will be determined according to the Content-Disposition of the requested content. If there is no Content-Disposition, then the last part of the requested URL will be used as the file name.

2. window.open

The above case of using a tag can also be achieved through window.open, the effect is the same, and the code is as follows:

window.open('[http://www.google.com'](http://www.baidu.com'), '_blank')

The _blank here is the way to specify the opening. If not specified, it will be opened on the current page. Specifying _blank here means opening it on a new page. The download attribute of a tag can also be used, the code is as follows:

window.open('[http://www.google.com'](http://www.baidu.com'), '_blank', 'download=google.html')

Of course, this method is also flawed. Compared with a tag, this method cannot download .html, .htm, .xml, .xhtml, and other files, because these files will be treated as HTML files, so they will be directly on the current page. Open.
It is also impossible to download cross-domain files. After all, it is window.open, not window.download (window.download is an imaginary).

3. location.href

This method is the same as window.open(url), the code is as follows:

location.href = '[http://www.google.com'](http://www.baidu.com')

This method has all the defects of window.open, so it is not recommended to use it. It is only used as an understanding here, so I will not explain it too much.

4. location.? Other properties

Others here refer to the properties that can jump to the page, such as location.assign, location.replace, location.reload, etc. These properties can realize file download, the code is as follows:

location.assign('[http://www.google.com'](http://www.baidu.com'))
location.replace('[http://www.google.com'](http://www.baidu.com'))
location.reload('[http://www.google.com'](http://www.baidu.com'))

The location.reload here is a bit special, its function is to reload the current page, but it can also accept a parameter, this parameter is the page to be jumped, so it can also achieve file download.
Of course, like location.href, these methods have the same disadvantages, and also have their own characteristics of each attribute. This is only to expand knowledge and not to explain too much.

5. XMLHttpRequest

This method is what we often call ajax download, including Axios, fetch, etc. are the same, the code is as follows:

const xhr = new XMLHttpRequest()
xhr.open('GET', '[http://www.google.com'](http://www.baidu.com'))
xhr.send()xhr.onload = function () {
  const blob = new Blob([xhr.response], { type: 'text/html' })
  const a = document.createElement('a')
  a.href = URL.createObjectURL(blob)
  a.download = 'google.html'
  a.click()
}
const xhr = new XMLHttpRequest()
xhr.open('GET', '[http://www.google.com'](http://www.baidu.com'))
xhr.send()xhr.onload = function () {
  const blob = new Blob([xhr.response], { type: 'text/html' })
  const a = document.createElement('a')
  a.href = URL.createObjectURL(blob)
  a.download = 'google.html'
  a.click()
}

I won’t talk about the knowledge related to XMLHttpRequest here, only the part related to file download.
The main logic here is that when our request is successful, we will get the response of the response body, this response is the content we want to download, and then we convert it into a blob object, and then create a url through URL.createObjectURL, and then File download is achieved through the download attribute of the a tag.
There are two knowledge points here, one is the blob object, and the other is URL.createObjectURL.

5.1 blob

Here is the definition of the blob object, from MDN:

The Blob object represents a blob, which is a file-like object of immutable, raw data; they can be read as text or binary data, or converted into a ReadableStream so its methods can be used for processing the data.Blobs can represent data that isn't necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system.

The blob object is a new object in html5. Its function is to store binary data, such as pictures, videos, audio, etc. Its usage is as follows:

/**
 * [@param](http://twitter.com/param) {Array}  array binary data
 * [@param](http://twitter.com/param) {Object} options configuration item
 *      [@param](http://twitter.com/param) {String} options.type The file type, which represents the MIME type of the array contents that will be put into the blob.
 *      [@param](http://twitter.com/param) {String} options.endings Used to specify how strings containing line terminators \n are written. Defaults to transparent, which means that line terminators will not be modified. It can also be specified as native, which means that \n will be converted to \r\n.
 */
const blob = new Blob([], { type: "" });

The main concern here is the type attribute. By default, the blob object has no type attribute, so the blob is an untyped blob, and the file will not be damaged, but it cannot be recognized normally.

5.2 URL.createObjectURL

The following is from MDN:

The URL.createObjectURL() static method creates a string containing a URL representing the object given in the parameter.The URL lifetime is tied to the document in the window on which it was created. The new object URL represents the specified File object or Blob object.

This method is used to create a url. Its function is to convert a blob object into a url. This url can be used to download files or preview files. The code is as follows:

const url = URL.createObjectURL(blob);

It should be noted here that the life cycle of this url is bound to the document in the window that created it, that is to say, when our document is destroyed, the url will be invalid, so we need to destroy it at the right time, code show as below:

URL.revokeObjectURL(url);

Back to the problem we just downloaded, we solved it through the blob object, but our type attribute is hard-coded. If the file type is determined, there is no problem, but if this interface is the interface for downloading files, Files can be of various types, what should we do with them?
There is no correct answer here. The first is to negotiate with the interface provider. The negotiation scheme is uncertain. The second is to obtain the type of the file through the header of the response, which is also what we want to talk about:

const type = response.headers["content-type"];
const blob = new Blob([response.data], { type });

Here we get the type through the header of the response, and then create the blob object, so that the file can be downloaded correctly.
In fact, content-type may also be application/octet-stream. At this time, we need to obtain the type of the file through file-type.
The following code uses file-type to get the type of the file:

import { fileTypeFromStream } from "file-type";
const type = await fileTypeFromStream(response.body);
const blob = new Blob([response.data], { type });

The use of file-type can be referred to here.

Summarize

There are so many solutions above, but in fact, it finally falls on a tag, so whether it is downloaded through the built-in behavior of the browser or downloaded through ajax, the final file download is the behavior of the browser.




Continue Learning