“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第3篇文章,点击查看活动详情”
背景
前端日常开发过程中,经常会遇到 下载文件 的需求。
之前常使用的方法:
收集所需参数传递给前置请求,请求返回文件下载地址或者文件id。利用 a 链接 download 属性 实现文件下载。
那么有没有方法直接实现文件下载那? 可以有。
就是让后端直接返回 blob文件流,前端发起一个请求实现对应下载。 本文主要介绍对应功能的实现。
实现思路
- 前端发起网络请求,指定响应类型,拿到后端返回的文件流,文件名。
- 利用 new Blob() 创造一个 Blob 对象
- 利用 URL.createObjectURL(blob) 创造url地址。
- 创建 a 元素,指定 href,download 等属性, 模拟点击实现下载。
- 利用 URL.revokeObjectURL() 释放url地址。
- 利用 removeChild 移除 a 元素。
函数封装
import axios from 'axios';
/**
* 发送 post 请求下载文件,文件返回的为blob流
* @param {*} url 接口地址
* @param {*} data 请求参数
* @param {*} fileName 文件名
*/
export default async function fileDownload(url, data, fileName) {
try {
await axios({
url: url,
method: 'post',
data: JSON.stringify(data),
responseType: 'blob', //指定blob
headers: {
'Content-Type':'application/json;',
// token 等其它所需请求头
}
}).then((res)=> {
const content = res.data;
const contentType = res.headers['content-type'] || 'application/octet-stream';//解决兼容性
const blob = new Blob([content], {type:contentType});
// 文件名一般后端会返回,调用方法时不需要传入。如果不返回,需要前端传入
// 具体在header里面那个字段返回需要协商, 此处只是一种方式,可自行修改。
if (!fileName) { //未传入fileName, 从header里面取
if (res.headers['fileName']) {
fileName = decodeURI(res.headers['fileName']); // 注意解码
}
}
if ('download' in document.createElement("a")) { //非ie
const fileLink = document.createElement("a");
fileLink.download = fileName;
fileLink.style.display = 'none';
fileLink.href = URL.createObjectURL(blob);
document.body.appendChild(fileLink);
fileLink.click();
URL.revokeObjectURL(fileLink.href); //释放url对象
document.body.removeChild(fileLink);
} else {
navigator.msSaveBlob(blob, fileName);
}
});
} catch(e) {
}
}
注意:application/octet-stream 解决火狐等兼容性。
函数调用
调用对应函数,传入对应参数即可。
let isDownloading = true;
fileDownload(url, data).then(()=>{
isDownloading = false;
})
总结
按照对应思路实现即可,每天进步一点点。
点赞评论是更新的动力,jym 动动小手支持下吧!