🔥利用koa实现前后端文件下载[完整前后端代码]

前言

文件下载功能是一个常用的功能,一个项目中或多或少都会用到,那么这么一个常用的功能,前后端代码如何实现呢?

为什么我们不通过url的方式直接下载?

如果我们使用a标签直接下载会有哪些问题?

  1. 跨域下载问题:如果要下载的文件与当前页面不在同一个域下,浏览器可能会阻止跨域下载。这是因为浏览器实施了同源策略,限制跨域资源的访问。
  2. 兼容性问题:使用<a>标签直接下载文件可能在不同浏览器之间存在兼容性问题。不同浏览器对文件下载的实现方式和行为可能有所不同。有的浏览器可能就是直接打开文件

上面的问题,有什么解决办法?

  1. 针对第一种问题,如果是非同源url,可以使用blob: URLsdata: URLs个(不建议使用base64这种方式,因为如果文件体积大的话,那么base64转化后会变为原体积的4/3,所以base64只适合小文件或者小文本)
  2. 第二种问题可以使用<a>标签模拟点击下载,这可以在一定程度上抹平浏览器差异,因为这种方法触发了浏览器的默认行为

不通过url的方式接受,那么我们就通过二进制的方式接受文件

后端是采用buffer还是stream呢?

其实两种都可以

fs和buffer,stream的关系是什么?

BufferStream再到fs模块,对数据处理的粒度是越来越大的。而Node.jsfs模块的实现上确实也是继承了上述两个模块的api来实现的。

  • 继承Stream的文件流,对外暴露fs.createReadStreamfs.createWriteStream

  • 对文件的同步与异步操作

    • fs.readFileSyncfs.writeFileSync
    • fs.readFilefs.writeFile
  • 以上两种fs处理文件的形式,区别在于第一种的处理会将文件处理为流的形式。第二种会将文件视作一个整体,统一为整个文件分配内存大小,并将内容放入到一个大的缓冲区中。

前端注意设置responseType

在前端发起请求时,可以通过设置responseType(注意分清content-type和responseType,content-type是表示请求的中的实体主体的媒体类型,会显示在请求头中。 responseType是指定服务器返回数据的类型,是请求配置信息)属性来指定服务器返回数据的类型,以便浏览器正确解析响应内容。responseType属性可以设置为以下几种值:

  1. """text":默认值,将响应数据解析为字符串。
  2. "arraybuffer":将响应数据解析为ArrayBuffer对象。适用于处理二进制数据,例如图片或音频。
  3. "blob":将响应数据解析为Blob对象。适用于处理二进制数据,例如文件下载。
  4. "document":将响应数据解析为Document对象。适用于处理XML或HTML响应。
  5. "json":将响应数据解析为JSON对象。适用于处理JSON格式的数据。

通过设置responseType属性,可以告诉浏览器如何解析响应数据,以便后续对数据进行处理。例如,如果需要下载图片文件,可以将responseType设置为"blob",将响应数据解析为Blob对象,然后可以通过创建URL或者使用FileReader等进行进一步处理。

需要注意的是,设置responseType属性并不会自动转换响应数据的格式,仅仅是告诉浏览器如何解析响应内容。如果服务器返回的数据格式与设置的responseType不一致,可能会导致解析错误或数据丢失。因此,需要根据服务器返回的数据类型来正确设置responseType属性。

所以:

    1. 如果我们使用stream传输的话,可以设置responseTypeblob
    1. 如果我们使用buffer传输的话,可以设置responseTypearraybuffer

把上面的概念都理清了以后,那么代码就好写了

我们先开始使用stream传输

前端代码

js 复制代码
//返回二进制数据或文件流下载
const downLoadFile = async () => {
   const res = await axios({
    url: "http://localhost:9001/api/download/file",
    method: "get",
    responseType: "blob", // 返回的就是blob格式
  });
  // 获取blob
  let blob = res.data;
  let fileName = "12.jpeg";
  //
  const url = URL.createObjectURL(blob);
  // 创建一个隐藏的链接,并设置其下载属性和链接地址
  const link = document.createElement("a");
  link.style.display = "none";
  link.href = url;
  link.download = fileName;

  // 将链接添加到页面上,并触发点击事件进行下载
  document.body.appendChild(link);
  link.click();

  // 下载完成后,清除链接和释放URL对象
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
};

后端代码

js 复制代码
router.get('/', (ctx: any) => {
  const filename = '1.jpeg';
  const filePath = path.resolve(__dirname, `../../public/upload/${filename}`);
  const stream = fs.createReadStream(filePath);
  ctx.body = stream;
});

使用buffer传输

前端代码

ini 复制代码
const res = await axios({
    url: "http://localhost:9001/api/download/file",
    method: "get",
    responseType: "arraybuffer",
  });
  // 获取buffer
  let blob = new Blob([res.data]);
  let fileName = "12.jpeg";
  //
  const url = URL.createObjectURL(blob);
  // 创建一个隐藏的链接,并设置其下载属性和链接地址
  const link = document.createElement("a");
  link.style.display = "none";
  link.href = url;
  link.download = fileName;

  // 将链接添加到页面上,并触发点击事件进行下载
  document.body.appendChild(link);
  link.click();

  // 下载完成后,清除链接和释放URL对象
  document.body.removeChild(link);
  URL.revokeObjectURL(url);

后端代码

js 复制代码
router.get('/', (ctx: any) => {
  const filename = '1.jpeg';
  const filePath = path.resolve(__dirname, `../../public/upload/${filename}`);
  const file = fs.readFileSync(filePath);
  ctx.body = file;
});

总结

  1. 上面我们讲了我们为什么不使用url的方式下载,讲了使用url下载的问题,以及针对这些问题我们应该如何去解决
  2. 讲解了后端采用buffer和stream两种方式获取文件二进制信息
  3. 讲了针对后端采用不同的方式,前端应该如何去接收

参考

相关推荐
一颗花生米。22 分钟前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
学习使我快乐0126 分钟前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio199527 分钟前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
勿语&1 小时前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
一路向前的月光6 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   6 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web6 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
Jiaberrr7 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
安冬的码畜日常9 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
太阳花ˉ9 小时前
html+css+js实现step进度条效果
javascript·css·html