There are still many application scenarios for file downloads involved in the front-end, so how many ways are there for front-end file downloads? What are the advantages and disadvantages of each method? Let's introduce them one by one.
1. a label
It is the simplest way to realize file download through the attribute a
of the label , and it is also a common way we use. Let’s look at the sample code first:download
<a href="http://www.baidu.com" download="baidu.html">下载</a>
For the above example, we clicked download and found that it jumped to Baidu's homepage, 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, it includes media files such as pictures, audio and video, which are all previews and cannot be downloaded.
The above code is a
to realize the file download directly by writing the label, we can also js
realize it by writing, the code is as follows:
const a = document.createElement('a')
a.href = 'http://www.baidu.com'
a.download = 'baidu.html'
a.click()
The effect is the same as above, all jump to Baidu's homepage without downloading files.
The key point here is the attribute a
of the label , which is newly added.download
HTML5
Content-Disposition
Its function is to specify the downloaded file name. If not specified, the downloaded file name will be determined according to the content of the request . If not Content-Disposition
, URL
the last part of the request will be used as the file name.
2. window.open
The above a
case of using tags can also window.open
be achieved by using the same effect, the code is as follows:
window.open('http://www.baidu.com', '_blank')
Here _blank
is the specified opening method, if not specified, it will be opened on the current page, if specified here _blank
, it will be opened on a new page.
The attributes of the same a
tag download
can also be used, the code is as follows:
window.open('http://www.baidu.com', '_blank', 'download=baidu.html')
Of course, this method is also flawed. Compared with a
tags, this method cannot download .html
, .htm
, .xml
, .xhtml
and other files, because these files will be html
treated as files, so they will be opened directly on the current page.
Similarly, cross-domain files cannot be downloaded, after all, yes window.open
, no window.download
( window.download
hypothetical).
3. location.href
This method is window.open(url)
the same as that, the code is as follows:
location.href = 'http://www.baidu.com'
This method has window.open
all the flaws, so it is not recommended to use, here is only for understanding, so I will not explain too much.
4. location.? other attributes
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.baidu.com')
location.replace('http://www.baidu.com')
location.reload('http://www.baidu.com')
Here location.reload
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 realize file download.
Of course location.href
, the disadvantages of these methods are the same, and there are also the characteristics of each attribute. This is only to expand knowledge, not to explain too much.
5. XMLHttpRequest
This method is what we often call ajax
downloading, including axios
, fetch
etc. are the same, the code is as follows:
const xhr = new XMLHttpRequest()
xhr.open('GET', '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 = 'baidu.html'
a.click()
}
XMLHttpRequest
I won’t talk about related knowledge here , but only talk about the part related to file download.
The main logic here is that when our request is successful, we will get the response body response
, which response
is the content we want to download, and then we convert it into an blob
object , and then URL.createObjectURL
create a file through the attribute of the tag download.url
a
download
There are two knowledge points here, one is blob
the object and the other is the object URL.createObjectURL
.
5.1 blob
Here is blob
the definition of the object, from MDN [2]:
Blob
Object represents a file-like object of immutable, primitive data. Its data can be read in text or binary format, and can also be convertedReadableStream
for data manipulation.
Blob
Represents not necessarilyJavaScript
data in its native format.File
The interface is based onBlob
, inheritedblob
functionality from and extended to support files on the user's system.
blob
Object is html5
a newly added object, and its function is to store binary data, such as pictures, videos, audio, etc. Its usage is as follows:
/**
* @param {Array} array 二进制数据
* @param {Object} options 配置项
* @param {String} options.type 文件类型,它代表了将会被放入到 blob 中的数组内容的 MIME 类型。
* @param {String} options.endings 用于指定包含行结束符\n的字符串如何被写入。默认为transparent,表示不会修改行结束符。还可以指定为native,表示会将\n转换为\r\n。
*/
const blob = new Blob([], { type: '' })
The main concern here is type
the attribute. By default, blob
the object has no type
attribute, so this Blob
is a typeless Blob
file. The file will not be damaged, but it cannot be recognized normally.
5.2 URL.createObjectURL
The following is from MDN [3]:
The URL.createObjectURL() static method creates a DOMString containing a URL representing the object given in the parameter. The lifetime of this URL is bound to the document in the window that created it. This new URL object represents the specified File object or Blob object.
This method is used to create one url
. Its function is to blob
convert an object into one url
. This method url
can be used to download files or preview files. The code is as follows:
const url = URL.createObjectURL(blob)
What needs to be noted here is that url
the life cycle of this is bound to the window that created it document
, that is to say, when ours document
is destroyed, this url
will become invalid, so we need to destroy it at the right time. The code is as follows:
URL.revokeObjectURL(url)
Going back to the problem we just downloaded, we blob
solve it through objects, but our type
attributes are hard-coded. If the file type is determined, there is no problem, but if this interface is the interface for downloading files, the file may There are various types, how should we deal with them?
There is no correct answer here. The first one can be negotiated with the interface provider. The negotiation plan is uncertain. The second is to obtain the file through response
it , which is what we want to talk about:header
type
const type = response.headers['content-type']
const blob = new Blob([response.data], { type })
Here we get it response
through , and then create the object, so that the file can be downloaded correctly.header
type
blob
In fact , content-type
it may be that application/octet-stream
at this time we need to file-type
get the file through type
.
The following code is passed file-type
to get the file type
:
import {fileTypeFromStream} from 'file-type';
const type = await fileTypeFromStream(response.body);
const blob = new Blob([response.data], { type })
6. Summary
There are so many solutions above, in fact, it still falls on a
the label in the end, so whether it is downloaded through the built-in behavior of the browser or through ajax
the download, the final file download is the behavior of the browser.
---END---