首页 > 技术文章 > Axios发送请求下载文件(重写二进制流文件)

art-poet 2020-09-25 16:38 原文

用axios正常发送请求下载excel会出现以下问题,即将二级制流文件下载到了本地,下附解决办法:

 一、实现思路:

这类方法思路如下:

1. 使用js在页面常见a标签

2. 创建Blob对象, 在Blob中传入后端返回的response.data

   这一步中Blob需要的是一个数组类型的参数, 后端二进制流这边接收到的response.data使用查看发现是String, 所以我把response.data放进一个长度1的数组, 再传入Blob对象,

   此外需要规定文件类型, 可以是doc的(这里传的word文档)application/vnd.openxmlformats-officedocument.wordprocessingml.document, 也可以是二进制流的application/actet-stream

3. 创建下载链接 window.URL.createObjectURLblob()

4. 把3创建的链接变量赋值个a标签的href属性(这类用法详见a标签文档)

5. 使用document.body.appendChild把a标签挂上去, 再调用a标签的.click()事件

6. document.body.removeChild(a标签) 移除a标签

7.window.URL.revokeObjectUR()下载链接)释放blob对象

 

二、get请求下载流文件:

1、使用 responseType: 'blob' 下载文件

第一步:让后端将下载的接口的response header设置:

Content-disposition: attachment; filename=数据报表.xlsx(表示会直接下载文件,文件名为‘数据报表’)

Content-Type:application/octet-stream  (二进制流数据,如常见的文件下载)

第二步:修改axios请求的responseType为blob,以get请求为例:

第三步:请求成功,拿到response后,调用下载函数

  //get下载
  onFileDownload = (index,item) => {
    request.get('/file/records/download', {
      params: {
        //这里是参数
      },
      responseType: 'blob',//响应类型为流
      onDownloadProgress:(ProgressEvent) => {//用来计算下载量(实际项目中可以用来显示下载进度)
        let total = item.fileLength;
        // console.log(ProgressEvent);
        let load = ProgressEvent.loaded;
        // console.log(load);
      }
    }).then((resp:any) => {
      if(resp) {
        let blob = new Blob([resp]);
        let url = window.URL.createObjectURL(blob);
        let link = document.createElement('a');
        link.href = url
        link.download = item.fileName || '下载文件';//下载后文件名
        document.body.appendChild(link);
        link.click();//点击下载
        link.remove();//下载完成移除元素
        window.URL.revokeObjectURL(link.href); //用完之后使用URL.revokeObjectURL()释放;
      }else {
        Message.error('文件下载失败,请重试!');
      }
    }).catch(e => {
      Message.error('暂无下载该文件的权限!');
    }).finally(() => {
      //请求结束回调
    })
  }

 或

download(){
  this.$http({
    method:"get",
    url:接口地址+"?data="+encodeURI(JSON.stringify(data)),
    responseType:'blob'
    }).then((res)=>{
      //这里res.data是返回的blob对象
      var blob = new Blob([res.data], {type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8'}); //application/vnd.openxmlformats-officedocument.wordprocessingml.document这里表示doc类型
        var contentDisposition = res.headers['content-disposition'];  //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
      var patt = new RegExp("filename=([^;]+\\.[^\\.;]+);*");
      var result = patt.exec(contentDisposition);
      var filename = result[1];
      var downloadElement = document.createElement('a');
      var href = window.URL.createObjectURL(blob); //创建下载的链接
      downloadElement.style.display = 'none';
      downloadElement.href = href;
      downloadElement.download =filename ; //下载后文件名
      document.body.appendChild(downloadElement);
      downloadElement.click(); //点击下载
      document.body.removeChild(downloadElement); //下载完成移除元素
      window.URL.revokeObjectURL(href); //释放掉blob对象
    })
}

 

三、post请求下载流文件:

第一步:让后端将下载的接口的response header设置:

Content-disposition: attachment; filename=数据报表.xlsx(表示会直接下载文件,文件名为‘数据报表’)

Content-Type:application/octet-stream  (二进制流数据,如常见的文件下载)

第二步:修改axios请求的responseType为blob,以post请求为例:

第三步:请求成功,拿到response后,调用下载函数

//文件下载
  onFileDownLoad(){
    request.post('/talent/demand/export',{
        //下载参数
      },
      {
        responseType: "blob"//指定响应类型
      }
    ).then((data:any) => {
      if(data) {
        if (!data) {
            return
        }
        let userInfo = this.getLoginNo()
        let url = window.URL.createObjectURL(new Blob([data]))
        let link = document.createElement('a')
        link.style.display = 'none'//设置隐藏创建的标签
        link.href = url
        link.setAttribute('download', `下载文件-${(new Date()).valueOf()}-${userInfo['empName']}(${userInfo['empId']}).xlsx`)//下载文件名称
        document.body.appendChild(link)
        link.click()//点击下载
        link.remove();//下载后移除
        window.URL.revokeObjectURL(link.href); //用完之后使用URL.revokeObjectURL()释放;
      }else {
        Message.error('下载出错,请重试!');
      }
    }).catch(e => {
      Message.error('暂无下载该文件的权限!');
    })
  }

 或

download(){
  this.$http({
    method:"post",
    url: 接口url,
    data:JSON.stringify(data),
    responseType:'blob',
    headers: {
      'Content-Type': 'application/json;charset=UTF-8'    //后端ssm框架接收json类型
    }
  }).then((res)=>{
  //这里res.data是返回的blob对象
  var blob = new Blob([res.data], {type: 'application/actet-stream;charset=utf-8'});
  var contentDisposition = res.headers['content-disposition'];  //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
  var patt = new RegExp("filename=([^;]+\\.[^\\.;]+);*");
  var result = patt.exec(contentDisposition);
  var filename = result[1];
  var downloadElement = document.createElement('a');
  var href = window.URL.createObjectURL(blob); //创建下载的链接
  downloadElement.style.display = 'none';
  downloadElement.href = href;
  downloadElement.download =filename ; //下载后文件名
  document.body.appendChild(downloadElement);
  downloadElement.click(); //点击下载
  document.body.removeChild(downloadElement); //下载完成移除元素
  window.URL.revokeObjectURL(href); //释放掉blob对象
  })
}

 

四、其他下载方法:

1、下载时创建a标签;

let formElement = document.createElement('form'); 
formElement.style.display = "display:none;"; 
formElement.method = 'post'; 
formElement.action = ${apiBasePath}/api/xxxxx/downloadDetailData; 
formElement.target = 'callBackTarget'; 
let inputElement = document.createElement('input'); 
inputElement.type = 'hidden'; 
inputElement.name = "params" ; 
inputElement.value = params; 
formElement.appendChild(inputElement); 
document.body.appendChild(formElement); 
formElement.submit(); 
document.body.removeChild(formElement);

缺点:该种方式下载传给后端的参数类型为:"application/x-www-form-urlencoded",且不支持修改传参类型。

 

2、get请求简单下载:

  //get拼接下载
  tableDataExport(){
    const data = {
      ...this.state.params,
      orderType: this.state.orderType,
      pageSize: undefined,
      pageNo: undefined,
      sortBy: undefined,
    }
    let loadData:any = ''
    for (let item in data){
      if(item && data[item]){
        if(isNaN(Number(data[item]))){
          loadData += item + '=' + data[item] + '&'
        }else{
          loadData += item + '=' + Number(data[item]) + '&'
        }
      }
    }
    window.location.href = config.baseURL + '/api/xxxx?' + loadData
  }

3、浏览器get下载使用window.open下载

var downURL = '下载接口'  

var getData = '?starTime=20180922&endTime=20180925'

var request = downURL+getData

window.open(request)

 

推荐阅读