前端文件下载(二)

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

本文,我们将通过案例,讲解如何将文件内容转成 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 的名称,包含文件后缀,否则生成的文件没有后缀
  • 自动唤起浏览器的下载,下载进度由浏览器控制
相关推荐
BillKu3 小时前
Vue3 + Element-Plus 抽屉关闭按钮居中
前端·javascript·vue.js
DevilSeagull3 小时前
JavaScript WebAPI 指南
java·开发语言·javascript·html·ecmascript·html5
面向星辰4 小时前
html中css的四种定位方式
前端·css·html
Async Cipher4 小时前
CSS 权重(优先级规则)
前端·css
大怪v4 小时前
前端佬:机器学习?我也会啊!😎😎😎手“摸”手教你做个”自动驾驶“~
前端·javascript·机器学习
Liquad Li5 小时前
Angular 面试题及详细答案
前端·angular·angular.js
期待のcode5 小时前
Spring框架1—Spring的IOC核心技术1
java·后端·spring·架构
用户21411832636025 小时前
首发!即梦 4.0 接口开发全攻略:AI 辅助零代码实现,开源 + Docker 部署,小白也能上手
前端
Livingbody7 小时前
10分钟完成 ERNIE-4.5-21B-A3B-Thinking深度思考模型部署
后端
gnip7 小时前
链式调用和延迟执行
前端·javascript