在上一篇文章 前端文件下载(一)中,我们介绍了如何进行「超链接文件」下载
。
本文,我们将通过案例,讲解如何将文件内容转成 Blob
下载。
Blod 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成
ReadableStream
用来操作数据。
本文因为已经将文件转为 Blob
了,这里可以忽略跨域请求。我们直接在同源下进行案例演示。(文末有给出理由~)
下面,我们新建一个简单的 SSR
应用。
案例的环境(Main) mac m1 node version - v14.18.1 Google Chrome: 版本 116.0.5845.187(正式版本) (arm64)
案例
我们依旧拿 test.txt.zip
文件作为演示案例文件:
const Koa = require('koa');
const Router = require('koa-router');
const views = require('koa-views');
const path = require('path');
const fs = require('fs');
const app = new Koa();
const router = new Router();
// ejs template
app.use(
views(path.join(__dirname, 'views'), {
extension: 'ejs'
})
);
router.get('/', async (ctx) => {
await ctx.render('index'); // render
});
router.get('/download/file', async (ctx) => {
const filePath = path.join(__dirname, 'public', 'test.txt.zip');
ctx.attachment(filePath);
ctx.type = 'application/octet-stream';
ctx.body = fs.createReadStream(filePath); // create read stream
});
app.use(router.routes());
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
我们在路由 /
中渲染了模版文件,然后在路由 /download/file
中,将文件 test.txt.zip
转为可读流返回。
渲染的模版内容如下:
代码语言:javascript复制<!DOCTYPE html>
<html>
<head>
<title>SSR Download File</title>
</head>
<body>
<h1>Hello, Jimmy!</h1>
<button id="download">Download File</button>
<script>
(function(){
let downloadBtn = document.getElementById("download");
downloadBtn.addEventListener('click', function(){
fetch('/download/file')
.then(response => response.blob())
.then(blobData => {
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(blobData); // createObjectURL
downloadLink.download = 'demo.txt.zip'; // should add, or filename extension not work
downloadLink.click();
URL.revokeObjectURL(downloadLink.href); // revoke
})
})
})()
</script>
</body>
</html>
在模版中,我们请求了接口 http://localhost:3000/download/file
返回的信息。然后 .then(response => response.blob())
将响应的数据转换成为 Blob
对象。之后配合 createObjectURL
将数据对象转成一个 url
,通过 a
标签进行下载。
为什么我们开篇说忽略跨域。因为
createObjectURL
转成的数据对象url
是在当前域名下生成,这里是http://localhost:3000/path/to
,可以查看downloadLink.href
的值。感兴趣读者可以在跨域下进行验证,比如:http://localhost:5500
,生成的对象url
将是http://localhost:3000/path/to
。
触发下载按钮后,我们将看到下载过程自动启动,文件被下载下来。
总结
本文中,我们使用 Blob
和 createObjectURL
,并集合了 fetch
进行文件的下载。它有以下的特点:
- 不受同源策略的限制 - 同源和跨域都可
- 需要设定
download
的名称,包含文件后缀,否则生成的文件没有后缀 - 自动唤起浏览器的下载,下载进度由浏览器控制