解决Ajax/Axios请求下载无效的问题


起因

公司用vue搭了一个前端,现在需要一个文件导出下载的功能,向后台发请求传参下载,too young的我当然是想当然的用了axios发了post请求,结果发现页面死活没有反应。因为后台也是我写的,为了确认不是后台代码的毛病,我把拦截关了用location.href试了试,发现可行,文件下载成功。那么问题就出在axios请求上了。

原因

众所周知,Ajax/Axios请求实际上是通过XMLHttpRequest实现的,具体请自行百度。
request请求只是个“字符型”的请求,即请求的内容是以文本类型存放的。文件的下载是以二进制形式进行,虽然可以读取到返回的response,但只是读取,无法执行。也就是说前端无法调用到浏览器的下载处理机制和程序。

解决方法

通过blob(用来存储二进制大文件)包装ajax(或axios)请求到的data数据,实现下载EXCEL(或其他如图片等)文件。
这里是看到了博客园炫冰G爱的一篇文章,通过blob封装实现下载,原文链接点击这里
原文:

//案例一
axios:设置返回数据格式为blob或者arraybuffer
如:
    var instance = axios.create({         ... //一些配置
        responseType: 'blob', //返回数据的格式,可选值为arraybuffer,blob,document,json,text,stream,默认值为json
    })
请求时的处理:
  getExcel().then(res => {
      //这里res.data是返回的blob对象    
      var blob = new Blob([res.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'}); //application/vnd.openxmlformats-officedocument.spreadsheetml.sheet这里表示xlsx类型
      var downloadElement = document.createElement('a');
      var href = window.URL.createObjectURL(blob); //创建下载的链接
      downloadElement.href = href;
      downloadElement.download = 'xxx.xlsx'; //下载后文件名
      document.body.appendChild(downloadElement);
      downloadElement.click(); //点击下载
      document.body.removeChild(downloadElement); //下载完成移除元素
      window.URL.revokeObjectURL(href); //释放掉blob对象
 })
//案例二
 
function createDownload(fileName, content){
    var blob = new Blob([content]);
    var link = document.createElement("a");
    link.innerHTML = fileName;
    link.download = fileName;
    link.href = URL.createObjectURL(blob);
    document.getElementsByTagName("body")[0].appendChild(link);
}
createDownload("download.txt","download file");
//案例三<br>
function downloadExport(data) {
  return axios.post(url, data).then((res)=>{
    const content = res
    const blob = new Blob(["\uFEFF" + content.data],{ type: "application/vnd.ms-excel;charset=utf-8"})
    const fileName = '卡密.xls'
    if ('download' in document.createElement('a')) { // 非IE下载
      const elink = document.createElement('a')
      elink.download = fileName
      elink.style.display = 'none'
      elink.href = URL.createObjectURL(blob)
      document.body.appendChild(elink)
      elink.click()
      URL.revokeObjectURL(elink.href) // 释放URL 对象
      document.body.removeChild(elink)
    } else { // IE10+下载
      navigator.msSaveBlob(blob, fileName)
    }
  });
}

下面是我的代码,前端部分:

//发送请求
exportExcel(param).then(res => {
    const blob = new Blob([res]);
    const fileName = '导出信息.xls';
    if ('download' in document.createElement('a')) { // 非IE下载
        const elink = document.createElement('a');
        elink.download = fileName;
        elink.style.display = 'none';
        elink.href = URL.createObjectURL(blob);
        document.body.appendChild(elink);
        elink.click();
        URL.revokeObjectURL(elink.href);// 释放URL 对象
        document.body.removeChild(elink);
    } else { // IE10+下载
        navigator.msSaveBlob(blob, fileName);
    }
});

这里在之后的测试中还存在一个问题,用Edge浏览器(没错就是巨硬家的那个)无法下载,在控制台看了一下,是因为response里什么都没有。考虑到Edge浏览器实在是…所以暂时没管它,加了个“使用Edge浏览器无法下载”的提示,之后有必要再改。至于Chrome,FireFox,360,IE等都OK。
后端部分:

@RequestMapping(value = "/exportExcelFile",method = {RequestMethod.GET,RequestMethod.POST})
    public ResponseEntity<byte[]> export(String deviceCode, String batchNo, @RequestParam(required = false, value = "streetIds") List<String> streetIds, String type) throws IOException {
        List<Object> models = getExportModelList(deviceCode,batchNo,streetIds,type);
        File file = getExportExcelFile(models,type);
        System.out.println(file.getName());
        byte[] fileBytes = FileUtils.readFileToByteArray(file);
        file.delete();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", "export.xls");
        return new ResponseEntity<>(fileBytes, headers, HttpStatus.CREATED);
    }

getExportModelList:获取数据
getExportExcelFile:将数据通过OutPutExcel类返回一个file(OutPutExcel是自写类,详情自行百度利用freemaker导出文件)

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐