详细讲解常用的四种 js 下载文件方式

1,469 阅读2分钟

1. a标签下载 —可以直接下载txt、png、pdf、exe、xlsx等类型文件

downFile = (url) => {
    const a = document.createElement('a');
    const fileName = 'xx'
    a.style.display = 'none';
    a.download = fileName;
    a.href = url;
    document.body.appendChild(a);
    a.click(); 
    document.body.removeChild(a);
     /*
      * download: HTML5新增的属性
      * url: 属性的地址必须是非跨域的地址
       */
  };

2. window.open下载

<body> 
    <button onclick="download('http://xxx.xxx.com/download?name=file.pdf')">
        window.open下载
    </button> 
       
     <script> 
     function download(url) {
         window.open(url, '_self'); 
         /** * _blank:在新窗口显示目标网页 
         * _self:在当前窗口显示目标网页 
         * _top:框架网页中在上部窗口中显示目标网页 
         /** 
     } 
     </script>
 </body>

优点:

  • 简单方便

缺点:

  • 会出现URL长度限制问题
  • 需要注意url编码问题
  • 无法获取下载进度
  • 无法在header中携带token做鉴权操作
  • 无法判断接口是否成功
  • 无法直接下载浏览器可直接预览的文件类型(txt、png、pdf会直接预览)

3. location.href 下载

<body> 
    <button onclick="download('http://xxx.xxx.com/download?name=file.pdf')">
        location.href下载
    </button> 
    <script> 
        function download(url) { 
            window.location.href = url; 
        } 
    </script> 
</body>

优点

  • 简单方便直接
  • 可以下载大文件(G以上)

缺点

  • 会出现URL长度限制问题
  • 需要注意url编码问题
  • 无法获取下载进度
  • 无法在header中携带token做鉴权操作
  • 无法直接下载浏览器可直接预览的文件类型(txt、png、pdf会直接预览)
  • 无法判断接口是否返回成功

4. 文件流转blob对象下载

 <button onclick="download()">文件流转blob对象下载</button>
 <script>
    download() {
        axios({
            url: 'http://xxx.xxx.com/download',
            method: 'post',
            responseType: 'blob', // 注意请求类型
        }).then(res => {
            const fileName = res.headers.content-disposition.split(';')[1].split('filename=')[1];
            const filestream = res.data;  // 返回的文件流
            // {type: 'application/vnd.ms-excel'}指定对应文件类型为.XLS (.XLS的缩写就为application/vnd.ms-excel)
            const blob = new Blob([filestream], {type: 'application/vnd.ms-excel'});
            // type 也可以其他类型,  {type: 'application/vpf'}, 或者不设置 该参数
            
            if ('download' in  document.createElement('a')) {
                const a = document.createElement('a');
                a.style.display = 'none'
                a.target = '_black'
                const href = window.URL.createObjectURL(blob); // 创建下载连接
                a.href = href;
                a.download = decodeURL(fileName);
                // download: HTML5新增的属性
                document.body.appendChild(a);
                a.click();

                window.URL.revokeObjectURL(href); // 释放掉blob对象
                document.body.removeChild(a); // 下载完移除元素
            } else if (window.navigator.msSaveBlob) {
                // 1.msSaveBlob:只提供一个保存按钮
                window.navigator.msSaveBlob(blob, fileName);
                // 或者 2.msSaveOrOpenBlob:提供保存和打开按钮
                window.navigator.msSaveOrOpenBlob(blob, fileName);
            } 
            
            // 一般提前约定好,没下面2种情况
            //  判断返回是json还是文件流,json弹出错误提示。文件流,进行本地保存,再创建a标签进行下载 
            
            else if (res.body.type !== 'application/json')  {
                var reader = new FileReader();
                reader.readAsDataURL(blob);            // onload当读取操作成功完成时调用
                reader.onload = function(e) {             
                var a = document.createElement('a');              // 获取文件名fileName
                var fileName = res.headers["content-disposition"].split("=");
                fileName = fileName[fileName.length - 1];
                fileName = fileName.replace(/"/g, "");
                a.download = fileName;
                a.href = e.target.result;              
                document.body.appendChild(a);
                a.click();             
                document.body.removeChild(a);
            } else {
                const reader = new FileReader();
                // 如果返回的是json 格式, filestream 替换成 res.data
                // 读取文本文件,(可以使用Txt打开的文件) , 弹出错误提示
                reader.readAsText(filestream, 'utf-8'); 
                reader.onload = function (e: any) {
                    const result = JSON.parse(reader.result+'');
                    if (result.status.description || result.status.message) {
                        this.$message.error(
                            result.status.description || result.status.message
                        );
                    } else {
                        this.$message.error('系统错误');
                    }
                };
            }

        })
    }
 </script>


优点:

  • 可以下载txt、png、pdf等类型文件
  • 可以在header中携带token做鉴权操作
  • 可以获取文件下载进度
  • 可以判断接口是否返回成功

缺点:

  • 兼容性问题,IE10以下不可用,注意Safari浏览器,官网给出 Safari has a serious issue with blobs that are of the type application/octet-stream
  • 将后端返回的文件流全部获取后才会下载

相关知识 New FileReader() 的使用

1:FileReader : 读取文件内容

  • readAsText() 读取文本文件,(可以使用Txt打开的文件)
  • readAsBinaryString(): 读取任意类型的文件,返回二进制字符串
  • readAsDataURL: 方法可以将读取到的文件编码成DataURL ,可以将资料(例如图片、excel文件)内嵌在网页之中,不用放到外部文件
  • abort: 中断读取

2:FileReader 提供一个完整的事件模型,用来捕获读取文件的状态

  • onabort:读取文件断片时触发
  • onerror:读取文件错误时触发
  • onload:文件读取成功时触发
  • onloadend:文件读取完毕之后,不管成功还是失败触发
  • onloadstart: 开始读取文件时触发
  • onprogress:读取文件过程中触发

New FileReader 的具体使用请看上篇

new FileReader 的使用