Skip to content

文件下载

文件下载一般分为两种场景:

  • 返回的资源链接地址
    • 不用考虑资源大小问题
  • 接口返回文件流

一、针对返回有明确资源地址的场景

1. form 表单提交

  • 为下载按钮添加 click 事件,点击时动态生成一个表单,利用表单提交的功能来实现文件的下载
    js
       /**
        * 下载文件
        * @param {String} path - 请求的地址
        * @param {String} fileName - 文件名
        */
        function downloadFile (downloadUrl, fileName) {
            // 创建表单
            const formObj = document.createElement('form');
            formObj.action = downloadUrl;
            formObj.method = 'get';
            formObj.style.display = 'none';
            // 创建input,主要是起传参作用
            const formItem = document.createElement('input');
            formItem.value = fileName; // 传参的值
            formItem.name = 'fileName'; // 传参的字段名
            // 插入到网页中
            formObj.appendChild(formItem);
            document.body.appendChild(formObj);
            formObj.submit(); // 发送请求
            document.body.removeChild(formObj); // 发送完清除掉
        }

2. a 标签的 download

html
<a href="example.jpg" download>点击下载</a>

<a href="example.jpg" download="test">点击下载</a> // 指定文件名

3. open或location.href

js
window.open('downloadFile.zip');

location.href = 'downloadFile.zip';

二、接口返回文件流

  • Blob对象

    • 调用api,将文件流转为 Blob 二进制对象
      • 注:IE10以下不支持。
    • 思路: 发请求获取二进制数据,转化为Blob对象,利用URL.createObjectUrl生成url地址,赋值在a标签的href属性上,结合download进行下载。
      javascript
         /**
          * 下载文件
          * @param {String} path - 下载地址/下载请求地址。
          * @param {String} name - 下载文件的名字/重命名(考虑到兼容性问题,最好加上后缀名)
          */
          downloadFile (path, name){
              const xhr = new XMLHttpRequest();
              xhr.open('get', path);
              xhr.responseType = 'blob';
              xhr.send();
              xhr.onload = function () {
                  if (this.status === 200 || this.status === 304) {
                      // 如果是IE10及以上,不支持download属性,采用msSaveOrOpenBlob方法,但是IE10以下也不支持msSaveOrOpenBlob
                      if ('msSaveOrOpenBlob' in navigator) {
                          navigator.msSaveOrOpenBlob(this.response, name);
                          return;
                      }
                      /*
                        如果发送请求时不设置xhr.responseType = 'blob',
                        默认ajax请求会返回DOMString类型的数据,即字符串。
                        此时需要使用两处注释的代码,对返回的文本转化为Blob对象,然后创建blob url,
                        此时需要注释掉原本的const url = URL.createObjectURL(target.response)。
                      */
                      /*
                        const blob = new Blob([this.response], { type: xhr.getResponseHeader('Content-Type') });
                        const url = URL.createObjectURL(blob);
                      */
                      const url = URL.createObjectURL(this.response); // 使用上面则注释此行
                      const a = document.createElement('a');
                      a.style.display = 'none';
                      a.href = url;
                      a.download = name;
                      document.body.appendChild(a);
                      a.click();
                      document.body.removeChild(a);
                      URL.revokeObjectURL(url);
                  }
              };
          }
      javascript
         // 使用axios
         downloadFile (path, name){
             axios.get({url: path, method: 'get' }).then(res => {
                 const blob = new Blob([res.data], { type: res.headers['content-type'] });
                 const url = URL.createObjectURL(blob);
                 const a = document.createElement('a');
                 a.style.display = 'none';
                 a.href = url;
                 a.download = name;
                 document.body.appendChild(a);
                 a.click();
                 document.body.removeChild(a);
                 URL.revokeObjectURL(url);
             })
         }
      • 该方法不能缺少a标签的download属性的设置。
      • 因为发请求时已设置返回数据类型为Blob类型(xhr.responseType = 'blob'),所以target.response就是一个Blob对象,打印出来会看到两个属性size和type。虽然type属性已指定了文件的类型,但是为了稳妥起见,还是在download属性值里指定后缀名,如Firefox不指定下载下来的文件就会不识别类型。
  • 利用Base64

    • 用法跟上面用 Blob 大同小异,基本上思路一样
    • 不同点: 上面是利用Blob对象生成 Blob URL, 这里则是生成 Data URL,即 base64 编码后的url形式。
      javascript
       /**
        * 下载文件
        * @param {String} path - 下载地址/下载请求地址。
        * @param {String} name - 下载文件的名字(考虑到兼容性问题,最好加上后缀名)
        */
        downloadFile (path, name){
            const xhr = new XMLHttpRequest();
            xhr.open('get', path);
            xhr.responseType = 'blob';
            xhr.send();
            xhr.onload = function () {
                if (this.status === 200 || this.status === 304) {
                    const fileReader = new FileReader();
                    fileReader.readAsDataURL(this.response);
                    fileReader.onload = function () {
                        const a = document.createElement('a');
                        a.style.display = 'none';
                        a.href = this.result;
                        a.download = name;
                        document.body.appendChild(a);
                        a.click();
                        document.body.removeChild(a);
                    };
                }
            };
        }

Released under the MIT License.