• a标签的下载


    基于a标签的下载,简易版本

    用fetch发送请求 对请求回来的二进制文件流进行处理

          fetch('/upload/user.png').then((res) => {
            res.blob().then((blob) => {
              const blobUrl = window.URL.createObjectURL(blob);
              // 这里的文件名根据实际情况从响应头或者url里获取
              const filename = 'user.txt';
              const a = document.createElement('a');
              a.style.display = 'none'
              //这里需要插入body的话,后面需要再移除
              a.href = blobUrl;
              a.download = filename;
              a.click();
              window.URL.revokeObjectURL(blobUrl);
            });
          });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
      如果是arraybuffer文件
      先把arraybuffer转化为
      生成Blob对象,设置type等信息
      const blobres = res.arrayBuffer();
      const fileBlob = new Blob([blobres],{ type: 'application/zip' })
      因为上面直接是blob对象,所以这里就接着,上面就ok了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1、 常规代码

    考虑火狐,下载多个场景

    ts
    复制代码
    // 检查浏览器型号和版本
    const useBrowser = () => {
        const ua = navigator.userAgent.toLowerCase();
        const re = /(msie|firefox|chrome|opera|version).*?([\d.]+)/;
        const m = ua.match(re);
        const Sys = {
            browser: m[1].replace(/version/, "'safari"),
            version: m[2]
        };
    
        return Sys;
    };
    
    ts
    复制代码
    const downloadByUrl = (url: string, filename: string) => {
        if (!url) throw new Error('当前没有下载链接');
    
        const a = document.createElement("a");
        //  火狐兼容
        if (useBrowser().browser === "firefox") {
            a.target = "_blank";
        }
        a.style.display = "none";
        a.href = url;
        a.download = filename;
        // 使用target="_blank"时,添加rel="noopener noreferrer" 
        //堵住钓鱼安全漏洞 防止新页面window指向之前的页面
        a.rel = "noopener noreferrer";
        document.body.append(a);
        a.click();
    
        setTimeout(() => {
            a.remove();
        }, 1000);
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    2、问题:

    1. 同源 URL 的限制
    2. 无法鉴权

    先发送请求获取 blob 文件流,这样就能在请求时进行鉴权;
    鉴权通过后再执行下载操作。

    Content-Disposition
    是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地

    3、分析问题呢

    同源就直接使用 download 下载
    跨域就先获取 blob,
    用 createObjectURL 或 readAsDataURL 读取链接,再用 download 下载。

    4、解决问题

    js
    复制代码
    import downloadByUrl from "@/utils/download";
    
    const download = async () => {
      const blob = await fetchFile();
    
      // 生成访问 blob 的 URL
      const url = URL.createObjectURL(blob);
    
      // 调用刚刚封装的 a 标签下载方法
      downloadByUrl(url, "表格文件.xlsx");
      
      // 删除映射,释放内存
      URL.revokeObjectURL(url);
    };
    
    
    js
    复制代码
    import downloadByUrl from "@/utils/download";
    
    const download = async () => {
      const blob = await fetchFile();
    
      // 声明一个 fileReader
      const fileReader = new FileReader();
      
      // 将 blob 读取成 base64
      fileReader.readAsDataURL(blob);
      
      // 读取成功后 下载资源
      fileReader.onload = function () {
          downloadByUrl(fileReader.result);
      };
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    注意点
    js
    复制代码
    export const fetchFile = async (params) => {
      return axios.get(api, {
        params,
        responseType: "blob"
      });
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5、总结

    URL.createObjectURL(blob) 可以直接访问,
    无需“编码/解码”,但需要记得撤销(revoke);

    而 Data URL 无需撤销(revoke)任何操作,
    但对大的 Blob 进行编码时,性能和内存会有损耗。

    总而言之,这两种从 Blob 创建 URL 的方法都可以用。
    但通常 URL.createObjectURL(blob) 更简单快捷。

  • 相关阅读:
    Nginx-反向代理如何配置
    python之ATM机存取款转账脚本
    你应该知道的 7 个很棒的 Java 项目
    G4012溧宁高速青云岭隧道隧道高清晰广播现场测试效果视频
    三分靠策略 七分靠执行
    Linux下MySQL安装问题解决以及注意事项(以腾讯云服务为主)
    挑战一周完成Vue3项目Day2:路由配置+登录模块+layout组件+路由鉴权
    PYTHON快捷键合集!学会让你成为大一最靓的仔
    【Linux实验】调用signal()函数来执行信号处理函数
    开源 C++ JSON 库 sonic-cpp解析性能为 rapidjson 的 2.5 倍
  • 原文地址:https://blog.csdn.net/qq_36262295/article/details/126689646