前端文件下载(二)

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

本文,我们将通过案例,讲解如何将文件内容转成 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 的名称,包含文件后缀,否则生成的文件没有后缀
  • 自动唤起浏览器的下载,下载进度由浏览器控制
相关推荐
华玥作者7 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_7 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
qq_297574677 小时前
【实战教程】SpringBoot 实现多文件批量下载并打包为 ZIP 压缩包
java·spring boot·后端
前端摸鱼匠7 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
sleeppingfrog7 小时前
zebra通过zpl语言实现中文打印(二)
javascript
lang201509287 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC8 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
未来之窗软件服务9 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
baidu_247438619 小时前
Android ViewModel定时任务
android·开发语言·javascript
嘿起屁儿整9 小时前
面试点(网络层面)
前端·网络