前端项目是如何实现文件下载的?
在业务开发中,我想大多数同学可能会遇到关于实现文件下载这方面的需求,例如说通过点击某一个小按钮或者标签来实现触发浏览器的下载功能
这里我先使用koa2
作为后端,起一个小小的Demo
在这个Demo
中我写了一个请求文件流的Api
,当客户端向这个Api
进行请求数据后,服务器端会返回一个File
接下来是前端部分了,我们用pnpm create vite
快速起一个项目,这里我就不再演示这个过程了
我简单的写了一个按钮并绑定了对应的请求函数,我们来看看network
中报文会返回什么数据
原来是跨域了,我们在vite.config.ts
中处理一下,通过设置代理的方式来解决跨域问题
接下来,我再请求一次看看
现在,服务器也将我们想要的文件返回的过来,但是作为用户我是要下载这个文件,而不是在请求中看到这个文件的内容
我们预期是效果应该是通过浏览器来下载这个文件
问题不大,我们写一个小小的函数简单的解决这个问题
typescript
function streamToDownloadFile(data: BlobPart, filename: string,type: string= 'application/octet-stream') {
let blob = new Blob([data], { type });
let url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
// 重命名文件
link.download = filename;
link.click();
URL.revokeObjectURL(url);
}
const download = () => {
console.log('download');
axios.get('/api/download/foo').then(res => {
// 触发浏览器下载机制
streamToDownloadFile(res.data, 'foo.txt')
})
}
注意,
download
属性是HTML5
的新特性
这样子我们的问题就解决了,当用户点击"下载文件"时,浏览器会自动把文件下载到客户端上面
在代码中我们写了一个streamToDownloadFile
函数,实现了将文件数据转换为可下载的文件并触发下载操作
主要步骤分为:
- 通过外部传入的文件数据和类型创建一个
Blob
对象 - 利用
createObjectURL
创建临时url
,引用Blob
对象的内容 - 创建a标签,设定href和download属性
- 通过click事件,触发浏览器下载机制
- 最后,使用
revokeObjectURL
释放之前创建的临时URL
,以防止内存泄漏
返回链接下载
除了后端返回文件流的方式,后端也可以返回一个文件地址给前端,然后前端根据文件地址请求触发浏览器下载
我们来模拟一下,这个场景
配置一下koa2
静态文件访问,需要安装pnpm add koa-static
这个包来实现静态资源的问题
这里,我们会遇到一个比较常见的问题,在
txt
、jpg
等文件用a
标签直接用href
属性,是不能实现下载功能的,浏览器会直接识别并显示这些文件
我们再写一个返回sheet.xlsx
文件的地址的Api
提供给前端使用
我们在前端请求下这个Api
,我们可以得到一个对象,包括文件名,下载文件链接(有点废话..)
这种情况下,我们要采用和上面一样的方法去处理这些格式文件去下载,所以我们这里把文件改为xlsx
文件进行测试
因为我的电脑上之前的安装了迅雷的扩展,所以默认有下载任务会被迅雷接管下载
这样,我们就实现了通过URL
的方式来下载文件
相比前面通过文件流下载文件的方式,这个方法会比较简单一些,不过有时候可能也会出现一些小Bug
,例如跳转后没有下载问题,而是打开文件
Demo
地址:file-download-demo