前端文件下载(二)

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

本文,我们将通过案例,讲解如何将文件内容转成 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 的名称,包含文件后缀,否则生成的文件没有后缀
  • 自动唤起浏览器的下载,下载进度由浏览器控制
相关推荐
万少6 小时前
HarmonyOS preview 预览文件 Kit 的入门讲解
前端
月屯6 小时前
平台消息推送(go)
数据库·后端·golang·cocoa·iphone·gin
q***31896 小时前
深入解析Spring Boot中的@ConfigurationProperties注解
java·spring boot·后端
IT_陈寒6 小时前
JavaScript 性能优化实战:我从 V8 源码中学到的 7 个关键技巧
前端·人工智能·后端
风象南6 小时前
从擦除到恢复:JSON 库是如何“还原” Java 泛型信息的
后端
jenchoi4136 小时前
软件供应链npm/pypi投毒预警情报【2025-11-09】
前端·安全·web安全·网络安全·npm·node.js
艾小码6 小时前
别再只会用默认插槽了!Vue插槽这些高级用法让你的组件更强大
前端·javascript·vue.js
Victor3566 小时前
Redis(121)Redis的数据恢复如何进行?
后端
JaguarJack6 小时前
CSS 也要支持 if 了 !!!CSS if() 函数来了!
前端·css
bagadesu6 小时前
IDEA + Spring Boot 的三种热加载方案
java·后端