js 下载文件

161 阅读2分钟

a标签下载

 <body>
   <button onclick="downloadEvt('http://192.168.66.183:13666/download?name=HAP.pdf')">a标签下载</button>
   <script>
     function downloadEvt(url, fileName = '未知文件') {
       const el = document.createElement('a');
       el.style.display = 'none';
       el.setAttribute('target', '_blank');
      /**
        * download的属性是HTML5新增的属性
        * href属性的地址必须是非跨域的地址,如果引用的是第三方的网站或者说是前后端分离的项目(调用后台的接口),这时download就会不起作用。
        * 此时,如果是下载浏览器无法解析的文件,例如.exe,.xlsx..那么浏览器会自动下载,但是如果使用浏览器可以解析的文件,比如.txt,.png,.pdf....浏览器就会采取预览模式
        * 所以,对于.txt,.png,.pdf等的预览功能我们就可以直接不设置download属性(前提是后端响应头的Content-Type: application/octet-stream,如果为application/pdf浏览器则会判断文件为 pdf ,自动执行预览的策略)
        */
       fileName && el.setAttribute('download', fileName);
       el.href = url;
       console.log(el);
       document.body.appendChild(el);
       el.click();
       document.body.removeChild(el);
     }
   </script>
 </body>

优点:

  • 可以下载txt、png、pdf等类型文件
  • download的属性是HTML5新增的属性href属性的地址必须是非跨域的地址,如果引用的是第三方的网站或者是前后端分离项目(调用后台的接口),这时dowmload就会不起作用。此时,如果

缺点:

  • a标签只能做get请求,所有url有长度限制
  • 无法获取下载进度
  • 无法在header中携带token做鉴权操作
  • 跨域限制
  • 无法判断接口是否返回成功
  • IE兼容问题

form标签下载

 <body>
   <button onclick="inputDownloadEvt('get', 'http://192.168.66.183:13666/download', 'name', 'HAP.pdf')">form标签下载</button>
   <script>
     /**
      * @param {String} method - 请求方法get/post
      * @param {String} url
      * @param {String} paramsKey - 请求参数名
      * @param {String} paramsValue - 请求参数值
     */
     function inputDownloadEvt(method, url, paramsKey, paramsValue) {
       const form = document.createElement('form');
       form.style.display = 'none';
       form.setAttribute('target', '_blank');
       form.setAttribute('method', method);
       form.setAttribute('action', url);
       const input = document.createElement('input');
       input.setAttribute('type','hidden');
       // 对于get请求 最终会拼成http://192.168.66.183:13666/download?name=HAP.pdf
       input.setAttribute('name', paramsKey);
       input.setAttribute('value', paramsValue);
       form.appendChild(input);
       document.body.appendChild(form);
       form.submit();
       document.body.removeChild(form);
     }
   </script>
 </body>

优点:

  • 兼容性好,不会出现URL长度限制
  • get和post都可以

缺点:

  • 无法获取下载进度
  • 无法在header中携带token做鉴权操作
  • 无法直接下载浏览器可直接预览的文件类型(txt、png、pdf会直接预览)
  • 无法判断接口是否返回成功

window.open 下载

 <body>
   <button 
     onclick="downloadEvt('http://192.168.66.183:13666/download?name=HAP.pdf')">
     window.open下载
   </button>
  
   <script>
     function downloadEvt(url) {
       window.open(url, '_self');
     }
   </script>
  
 </body>
 ​

优点:

  • 简单方便直接

缺点:

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

iframe下载

 <body>
   <button 
     onclick="downloadEvt('http://192.168.66.183:13666/download?name=HAP.pdf')">
     iframe下载
   </button>
  
   <script>
     // 批量下载时,动态创建a标签,会始终只下载一个文件,改为动态创建iframe标签
     function downloadEvt(url) {
       const iframe = document.createElement('iframe');
       iframe.style.display = 'none';
       iframe.src = url;
       document.body.appendChild(iframe);
       setTimeout(() => {
         document.body.removeChild(iframe);
       }, 200);
     }
   </script>
 </body>

优点:

  • 可以下载txt、png、pdf等类型文件

缺点:

  • 无法获取下载进度
  • 无法在header中携带token做鉴权操作
  • 无法判断接口是否返回成功
  • 兼容、性能差

location.href 下载

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

优点:

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

缺点:

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

ajax下载(blob)

     // blob导出文件
     downloadFile: (blob, fileName) => {
         try {
             const link = document.createElement('a')
             link.download = decodeURIComponent(fileName)
             link.style.display = 'none'
             link.href = URL.createObjectURL(blob)
             document.body.appendChild(link)
             link.click()
             URL.revokeObjectURL(link.href)
             document.body.removeChild(link)
         } catch (err) {
             this.disposeErrorResult(err)
         }
     },
     // method:get/post  url:路径  config:请求头配置  callback:下载方法(固定) params:post方法的请求参数
     downloadFileDataOrError: (method,url,config,callback,params) => {
         try {
             let configs_params=null;
             if(method=='post'){
                 configs_params={...params}
             }else{
                 configs_params={...config}
             }
             axios[method](url,{...configs_params},{
                 ...config,
             }).then(function (response) {
                 const blob2 = response.data.text()
                 blob2.then((result)=>{
                     let JSON_RESULT=''
                     try {
                         JSON_RESULT = JSON.parse(result);
                         Modal.error({title:JSON_RESULT.errorMessage} );
                     } catch (error) {
                         const blob = new Blob([response.data]);
                         let content_disposition = response.headers['content-disposition']
                         let fileName = null;
                         if(content_disposition){
                             if(content_disposition.includes('filename*=')){
                                 fileName = content_disposition.split(';')[1].split(`'`)[2]
                             }else{
                                 fileName = content_disposition.split('filename=')[1]
                                 if(['"',"'"].includes(fileName[0])&&['"',"'"].includes(fileName[fileName.length-1])){
                                     fileName = fileName.substring(1,fileName.length-1)
                                 }
                             }
                         }
                         callback(blob, fileName);
                     }
                 })
             }).catch(function (error) {
                 // alert(error);
             });
         } catch (err) {
             this.disposeErrorResult(err)
         }
     },
     async exportData(url, config, callback) {
         try {
             const response = await axios(url, config)
             const blob = new Blob([response.data])
             let content_disposition = response.headers['content-disposition']
             let fileName=null;
             if(content_disposition){
                 if(content_disposition.includes('filename*=')){
                     fileName = content_disposition.split(';')[1].split(`'`)[2]
                 }else{
                     fileName = content_disposition.split('filename=')[1]
                     if(['"',"'"].includes(fileName[0])&&['"',"'"].includes(fileName[fileName.length-1])){
                         fileName=fileName.substring(1,fileName.length-1)
                     }
                 }
                 typeof callback == 'function' && callback(blob, fileName)
             }
         } catch (err) {
             this.disposeErrorResult(err)
         }
     },
     // fetch导文件数据
     async exportDataFetch (url = "GET", config, callback = Util.downloadFile) {
         try {
             const response = await fetch(url, config)
             if (response.status !== 200) {
                 this.disposeErrorResult(response)
             }
             const blob = await response.blob()
             let content_disposition = response.headers.get('content-disposition')
             let fileName = null;
             if (content_disposition) {
                 if (content_disposition.includes('filename*=')) {
                     fileName = content_disposition.split(';')[1].split(`'`)[2]
                 } else {
                     fileName = content_disposition.split('filename=')[1]
                     if (['"', "'"].includes(fileName[0]) && ['"', "'"].includes(fileName[fileName.length - 1])) {
                         fileName = fileName.substring(1, fileName.length - 1)
                     }
                 }
                 typeof callback == 'function' && callback(blob, fileName)
             }
         } catch (err) {
             this.disposeErrorResult(err)
         }
     },