后端为 Koa2 框架项目
前端为 Vue3 项目,使用 Axios 作为网络请求库。js-file-download。
效果演示

后端
routes/download.js
| 12
 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
 })
 
 | 
前端
首先一个普普通通的按钮,定义一个点击事件。
| 12
 3
 4
 5
 6
 
 | <template><!-- 一个普通的点击事件 -->
 <button @click="downloadFile">
 点我下载
 </button>
 </template>
 
 | 
如果你用最简单的那种,a标签形式src放上下载路径。然后后端直接静态文件路径。也是可以的。
a标签的下载有新标签页的开启或闪烁,体验不太好,所以更推荐使用下面这种。
事件响应里面,这样写!
| 12
 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-cors 库 https://github.com/zadzbw/koa2-cors#exposeHeaders
| 12
 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',
 ],
 maxAge: 5,
 credentials: true,
 allowMethods: ['GET', 'POST', 'DELETE', 'PATCH', 'PUT', 'OPTIONS'],
 allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
 })
 )
 
 | 
示例仓库地址:koa2端  vue端
相关参考