前端文件下载(二)

在上一篇文章 前端文件下载(一)中,我们介绍了如何进行「超链接文件」下载

本文,我们将通过案例,讲解如何将文件内容转成 Blob 下载。

Blod 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 用来操作数据。

本文因为已经将文件转为 Blob 了,这里可以忽略跨域请求。我们直接在同源下进行案例演示。(文末有给出理由~)

下面,我们新建一个简单的 SSR 应用。

案例的环境(Main)

mac m1

node version - v14.18.1

Google Chrome: 版本 116.0.5845.187(正式版本) (arm64)

案例

我们依旧拿 test.txt.zip 文件作为演示案例文件:

javascript 复制代码
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 转为可读流返回。

渲染的模版内容如下:

html 复制代码
<!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

触发下载按钮后,我们将看到下载过程自动启动,文件被下载下来。

总结

本文中,我们使用 BlobcreateObjectURL,并集合了 fetch 进行文件的下载。它有以下的特点:

  • 不受同源策略的限制 - 同源和跨域都可
  • 需要设定 download 的名称,包含文件后缀,否则生成的文件没有后缀
  • 自动唤起浏览器的下载,下载进度由浏览器控制
相关推荐
earthzhang202128 分钟前
第3讲:Go垃圾回收机制与性能优化
开发语言·jvm·数据结构·后端·性能优化·golang
哆啦A梦15882 小时前
搜索页面布局
前端·vue.js·node.js
_院长大人_2 小时前
el-table-column show-overflow-tooltip 只能显示纯文本,无法渲染 <p> 标签
前端·javascript·vue.js
SevgiliD2 小时前
el-table中控制单列内容多行超出省略及tooltip
javascript·vue.js·elementui
thinktik3 小时前
AWS EKS 集成Load Balancer Controller 对外暴露互联网可访问API [AWS 中国宁夏区]
后端·kubernetes·aws
要加油哦~3 小时前
JS | 知识点总结 - 原型链
开发语言·javascript·原型模式
追逐时光者3 小时前
将 EasySQLite 解决方案文件格式从 .sln 升级为更简洁的 .slnx
后端·.net
驰羽3 小时前
[GO]GORM 常用 Tag 速查手册
开发语言·后端·golang
哆啦A梦15884 小时前
axios 的二次封装
前端·vue.js·node.js
阿珊和她的猫4 小时前
深入理解与手写发布订阅模式
开发语言·前端·javascript·vue.js·ecmascript·状态模式