Front-end implementation of file download
Front-end downloads are generally divided into two situations. One is that the back-end directly gives a file address, which can be downloaded by opening it through a browser. The other requires sending a request. The back-end returns binary stream data, and the front-end parses the stream data to generate a URL. , to achieve downloading.
1. location.href
For some file formats that cannot be recognized by the browser, you can directly enter the url in the address bar of the browser to trigger the download function of the browser. There is no problem with downloading a single file, but if you download multiple files, clicking too quickly will reset the previous request
Applicable scene:
- get request
- single file download
window.location.href = url;
Two, window.open
Similar to location.href
window.open(url);
Three, a label
Direct downloads only work with files that your browser doesn't recognize. If it is a file format supported by the browser, such as html, jpg, png, pdf, etc., the file download will not be triggered, but will be directly parsed and displayed by the browser. In this case, you can use the a tag to download the file, the download attribute The file name can be set. It is suitable for downloading a single file. If you download multiple files, clicking too fast will reset the previous request.
Applicable scene:
- get request
- single file download
- need custom filename
//写法1
const download = (filename, url) => {
let a = document.createElement('a');
a.style = 'display: none'; // 创建一个隐藏的a标签
a.download = filename;
a.href = url;
document.body.appendChild(a);
a.click(); // 触发a标签的click事件
document.body.removeChild(a);
}
// 写法2
<a href="/images/download.jpg" download="myFileName">
Note: Sometimes we still need to download directly for the file format recognized by the browser. You can declare the Content-Disposition information of the header of the file, tell the browser that the link is a download attachment link, and you can declare the file name
Content-Disposition: attachment; filename="filename.xls"
4. File flow
If you need to use a post request, and the backend returns a file stream, then the front end needs to convert the file stream into a link, and then download it. The binary stream looks like this: Applicable scenarios:
- post request
- get request
- multiple files
1. Method of request
Note: JQuery cannot be used because JQuery does not support the blob type.
Native js writing method
const req = new XMLHttpRequest();
req.open('POST', '/download/excel', true);
req.responseType = 'blob'; //如果不指定,下载后文件会打不开
req.setRequestHeader('Content-Type', 'application/json');
req.onload = function() {
var content = req.getResponseHeader("Content-Disposition") ;
// 文件名最好用后端返的Content-disposition
// 需要后端设置 Access-Control-Expose-Headers: Content-disposition 使得浏览器将该字段暴露给前端
var name = content && content.split(';')[1].split('filename=')[1];
var fileName = decodeURIComponent(name)
downloadFile(req.response,fileName)
};
req.send( JSON.stringify(params));
axios wording
download(url: string, body: any, fileName: string, method?) {
return axios({
method: method ||'post',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
url,
responseType: 'blob',
headers: {
//如果需要权限下载的话,加在这里
Authorization: '123456'
}
data: JSON.stringify(params),
timeout: 60 * 1000
}).then((res: any) => {
if (!res) {
message.error('下载失败')
return
}
console.log('res:', res)
let url = window.URL.createObjectURL(new Blob([res], {
type: 'application/vnd.ms-excel' }))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
if (!fileName || typeof fileName != "string") {
fileName = "下载文件"
}
link.setAttribute('download', fileName + '.xlsx')
document.body.appendChild(link)
link.click()
document.body.removeChild(link); //下载完成移除元素
window.URL.revokeObjectURL(url); //释放掉blob对象
})
}
2. How to download files
Download via URL.createObjectURL()
URL.createObjectURL()
The static method creates a DOMString containing a URL representing the object given in the parameter. The life cycle of this URL is bound to the document in the window that created it.
downloadFile:function(data,fileName){
// data为blob格式
var blob = new Blob([data]);
var downloadElement = document.createElement('a');
var href = window.URL.createObjectURL(blob);
downloadElement.href = href;
downloadElement.download = fileName;
document.body.appendChild(downloadElement);
downloadElement.click();
document.body.removeChild(downloadElement);
window.URL.revokeObjectURL(href);
}
Download via #FileReader.readAsDataURL()
readAsDataURL()
method reads the specified Blob or File object. The read operation is an asynchronous operation. When the read is completed, you can get a data:URL format string (base64 encoded) from the onload callback function through the result attribute of the instance object. This string is the content of the read file, which can be Put it in the href attribute of the a tag.
downloadFile:function(data,fileName){
const reader = new FileReader()
// 传入被读取的blob对象
reader.readAsDataURL(data)
// 读取完成的回调事件
reader.onload = (e) => {
let a = document.createElement('a')
a.download = fileName
a.style.display = 'none'
// 生成的base64编码
let url = reader.result
a.href = url
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
}
the difference between the two
- return value
FileReader.readAsDataURL(blob) can get a base64 string
URL.createObjectURL(blob) gets a memory url of the current file
- Memory
FileReader.readAsDataURL(blob) automatically clears the URL from the memory according to the js garbage collection mechanism. createObjectURL(blob) exists in the current document, and the clearing method is manually cleared by revokeObjectURL()
- Implementation modalities
FileReader.readAsDataURL(blob) is returned by callback, asynchronously executed
URL.createObjectURL(blob) is returned directly, synchronously executed
- multiple files
When FileReader.readAsDataURL(blob) processes multiple files at the same time, one file needs to correspond to one FileReader object
URL.createObjectURL(blob) returns in sequence, no effect
- Comparison of advantages
URL.createObjectURL(blob) obtains the address of the local memory container URL
, which is convenient for previewing. It is necessary to pay attention to the problem of manually releasing the memory, and the performance is excellent.
FileReader.readAsDataURL(blob) can be directly converted to base64
format and used directly for business
Five, plug-indownloadjs
download
npm install --save downloadjs
import plugin
import download from "downloadjs"
// or
const download = require('downloadjs')
use
export const downloadFile = (res, type, filename) => {
// 将二进制流转成blob对象
const blob = new Blob([res], {
type: type
})
// 调用插件方法
download(blob, filename, type);
}