JavaScript 中如何下载一个文件流数据

in JavaScript with 0 comment

此问题说简单也简单说复杂也复杂,衍生的知识点还是相对多一点点

以下列出参考文章,有助于理解整体思路和概念

参考文章:

  1. JS二进制文件转换:File、Blob、Base64、ArrayBuffer : https://www.cnblogs.com/yinpengfei/p/17280585.html
  2. arraybuffer、Blob、File、Buffer详解、作用以及相互转化 https://zhuanlan.zhihu.com/p/376721544

概念解释

首先,我们要清楚,在 Js向后端请求的过程中, Response 会产生哪些类型
我们可以打开 MDN responseType介绍查看 :https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/responseType

我们只需要关系这四种即可

作为请求方式,我们可以多种方式来获取对应的 responseType 数据,这里列出 axios 和 fetch文档

我们以 Fetch 举例,我们可以通过

response.arrayBuffer().then(function(buffer) {
  // do something with buffer
)}; 轻而易举的拿到对应 类型数据

其实我觉得挺难理解为什么需要 arrayBuffer 或者 blob,直接使用json 或者 text 不可以吗

的确,大部分数据使用这两种类型可以实现,但是我们必须考虑一些问题

比如

以上几种,最终都要用到 arrayBuffer,也就是二进制的实现,最简单的 0 和 1 在任何地方都能保证数据的有效兼容

如何实现文件流下载

这里我们使用 fetch来实现

例子一

const downloadAvatar = () => {

  const url =
    "https://avatars.githubusercontent.com/u/29169847?v=4&size=64";
  const contentType = "image/png";
  fetch(url)
    .then((res) => res.arrayBuffer())
    .then((buffer) => {
      const blob = new Blob([buffer], { type: "image/png" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = "头像.png";
      a.click();
      URL.revokeObjectURL(url);
    });
};
document.querySelector("button").addEventListener("click", function (e) {
  e.preventDefault();
  downloadAvatar();
  return false;
});

可以看到,我们通过检测其 content-type,然后将 arrayBuffer 转为 blob 并最后得到一个 objectUrl 最终实现下载

当然这是一个最简单的例子

例子二

现在我们要升级,后端返回的数据可能是json 可能是 text 也可以能是其他乱七八糟的,我们希望根据不同的类型定义去走不同的逻辑

const url =

    "https://avatars.githubusercontent.com/u/29169847?v=4&size=64";
  fetch(url)
    .then((res) => {
      const contentType = res.headers.get("content-type");
      if (contentType && contentType.includes("application/json")) {
        return res.json();
      }
      return res.arrayBuffer();
    })
    .then((data) => {
      if (data instanceof ArrayBuffer) {
        // 处理二进制数据
        const blob = new Blob([data], { type: "image/png" });
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = "头像.png";
        a.click();
        URL.revokeObjectURL(url);
      } else {
        // 处理 JSON 数据
        console.log("收到 JSON 数据:", data);
        // 这里可以根据 JSON 数据的内容执行不同的逻辑
        if (data.error) {
          alert("下载失败: " + data.error);
        } else if (data.avatarUrl) {
          // 如果 JSON 中包含头像 URL,继续下载
          downloadAvatarFromUrl(data.avatarUrl);
        }
      }
    })
    .catch((error) => {
      console.error("下载失败:", error);
      alert("下载失败,请稍后重试");
    });
};

我们可以通过 Response contentType 判断数据类型来实现逻辑处理

例子三

const url =

    "https://raw.githubusercontent.com/surest-sky/surest-sky/refs/heads/main/README.md";
  fetch(url)
    .then((res) => res.arrayBuffer())
    .then((buffer) => {
      console.log(buffer);
      const decoder = new TextDecoder();
      const text = decoder.decode(buffer);
      console.log(text);
    })
    .catch((error) => {
      console.error("下载失败:", error);
    });

虽然我们返回的依旧是arrayBuffer,但是我们可以通过 TextDecoder来进行解析,最后得到一个实际的text内容

Responses