后端为 Koa2 框架项目

前端为 Vue3 项目,使用 Axios 作为网络请求库。js-file-download。

效果演示

Kapture 2022-04-08 at 14.12.44

后端

routes/download.js

1
2
3
4
5
6
7
8
9
10
11
12
13
router.get('/file', async (ctx, next) => {
const file = fs.createReadStream(
path.join(__dirname, `../public/template/测试文件.txt`)
)

ctx.set({
// 通过此种方法,同时可以隐藏真实的文件路径和文件名称
'Content-Disposition': `attachment;filename=${encodeURIComponent(
'文件.txt'
)}`,
})
ctx.body = file
})

前端

首先一个普普通通的按钮,定义一个点击事件。

1
2
3
4
5
6
<template>
<!-- 一个普通的点击事件 -->
<button @click="downloadFile">
点我下载
</button>
</template>

如果你用最简单的那种,a标签形式src放上下载路径。然后后端直接静态文件路径。也是可以的。

a标签的下载有新标签页的开启或闪烁,体验不太好,所以更推荐使用下面这种。

事件响应里面,这样写!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup>
const downloadFile = async () => {
const file_res = await axios.get('http://localhost:3000/download/file', {
responseType: 'blob'
})
// contentDisposition 中存储的是文件名信息。
const contentDisposition = file_res.headers['content-disposition']
// 解决中文乱码问题
const filename = decodeURI(
contentDisposition.slice(
contentDisposition.search('filename=') + 'filename='.length
)
)
fileDownload(file_res.data, filename)
}
</script>

这样就好了,很简单。

哦对了,写完上面的,你可能会发现 file_res.headers 中没有 content-disposition 变量。

这个是由于koa2 端的默认跨域规则导致的。你需要在 koa2 的跨域配置进行一些修改。

我这边使用的是 koa2-corshttps://github.com/zadzbw/koa2-cors#exposeHeaders

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
app.use(
cors({
origin: function (ctx) {
if (ctx.url === '/test') {
return false
}
return '*'
},
exposeHeaders: [
'WWW-Authenticate',
'Server-Authorization',
// 这里,默认是不返回 Content-Disposition 属性的
'Content-Disposition',
],
maxAge: 5,
credentials: true,
allowMethods: ['GET', 'POST', 'DELETE', 'PATCH', 'PUT', 'OPTIONS'],
allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
})
)

示例仓库地址:koa2端 vue端

相关参考