vue项目中用axios通过post请求下载的excel文件,以及下载的excel文件打开为乱码的解决办法

第一次碰到下载文件用 post 的方法,之前都是用 get 方法,直接下载一个存在在服务器根目录下的文件。但是有时候碰到参数的数据量比较大的时候, get 方法就不合适了。这次后端定义的是 post 方法,返回给前端的是一个文件流。

get 方法这里不赘述,基本思路就是动态创建一个a标签,设置a标签的 href 属性为接口地址,动态传参,下载即可。

post 方法请求下载文件

直接上代码:

 

methods:{
  //导出模板
  exportTem(){ //最初的方法
    let url="/pmkpi/v1/restapi/file/download";  //后端的接口
    let param = this.downloadPam;  //我自己项目中的请求参数
    axios.post(url,param,{
      // responseType: 'arraybuffer'
      'responseType':'blob'
      }
    ).then(res=>{
      console.log('res=>',res); 
      if(res.status==200){
        this.exportFile(res)
      }else{  
        this.$message({
          message: '服务器错误',
          type: 'error',
          duration:2000
        });
      }
    }) 
  },
  exportFile(result){
    let contentDisposition = result.headers['content-disposition'];
    // 这里后端给的内容中,文件名字可能是驼峰式名称的 fileName ,或者是全部小写的 filename
    let filename = decodeURI(contentDisposition.split('fileName=')[1] || contentDisposition.split('filename=')[1]);
    // 注意这里的 result.data ,如果只传 result 的话,最后下载出来的excel文件,里面显示的是 [object Object]
    let blob = new Blob([result.data],{type: result.headers['content-type']});
    // let blob = new Blob([result.data],{type: "application/x-msdownload;charset=GBK"});
    // let blob = new Blob([result.data],{type: "application/x-msdownload"});
    // let blob = new Blob([result.data]);
    // let blob = new Blob([result.data],{type: "application/vnd.ms-excel"});
    let url = window.URL.createObjectURL(blob);
    if (window.navigator.msSaveBlob) {  //IE
      try {
        window.navigator.msSaveBlob(blob, filename);
      }
      catch (e) {
        console.log(e);
      }
    }
    else {  //非IE
      let link = document.createElement('a');
      link.style.display = 'none';
      link.href = url;
      link.setAttribute('download', filename);
      document.body.appendChild(link);
      link.click();
    }
    URL.revokeObjectURL(url); // 释放内存
  }
}

 

个人注解:

  1、代码写法都是自己上网搜的,参考了很多文章,基本都是这样的编码思路。

  2、post 方法请求错误的处理方法,是我自己随便写的,如果想对错误处理更详细的话可以参照另一篇文章:axios+post下载文件,以及接口报错处理

踩坑

代码写完之后,excel 文件也下载下来了,但是打开 excel 文件,显示的是乱码,如下图:

 

自己采用 postman 测试,下载下来的文件是正常的:

postman下载的文件显示是正常的,如下图:

 

排查原因

post 请求成功之后,后端返回的结果为文件流,如下图:

 在代码中把请求结果通过 console.log() 打印出来查看,结果如图:

 

 

上网搜了很多文章,几乎都是说要设置 responseType 值为 blob ,也有设置为 arraybuffer 的,我代码里面都设置了;

也有在  let blob = new Blob([result.data],{type: result.headers['content-type']}) 中加 type ,我看网上很多 type 值为  application/vnd.ms-excel ,但是这一次后端返回的是 application/x-msdownload ,我就把这两种都加上,一一测试,不管用什么方法改动代码,下载的excel 都是乱码。

最后在 vue axios 请求二进制流excel文件,response乱码  这片文章中,看网友的最后一个评论,才意识到可能是 mockjs 引起的,mock 把请求返回结果类型给修改了。这个问题在之前的文章中(https://www.cnblogs.com/zyt-it/p/12206887.html) 看到过,只是没有在意。

最后把项目中的 mock 模式关闭,一般在 main.js 文件中引入的有 mock,找到引入的代码,注释掉即可。

再次请求,看后端返回的结果:

 

 

mock 模式关闭后,后端返回的结果类型为 XMLHttpRequest ,之前没有关闭 mock 模式的时候,后端返回的结果类型被改为了 MockXMLHttpRequest

此时下载的 excel 打开已经不是乱码了。

总结:

  1、最重要的是代码中要设置 responseType 的值,无论设置 blob 或者 arraybuffer 都可以。

  2、设置 responseType 后,代码 new Blob([result.data]) 中是否设置 type 值已经不重要了,即使不设置,也可以下载文件。如果设置的话:

    可以根据后端的字段动态设置:new Blob([result.data],{type: result.headers['content-type']}) 

    也可以根据后端返回的值写死:new Blob([result.data],{type: "application/x-msdownload;charset=GBK"})

    也可以不要编码:new Blob([result.data],{type: "application/x-msdownload"})

    也可以忽略后端的返回值,直接设置:new Blob([result.data],{"application/vnd.ms-excel"})

    总之:只要加了 responseType ,这里的 type 怎么写已经无所谓了。

  3、划重点了!!!!如果依照上面的写法,下载的 excel 依然是乱码,就要看 vue 项目中是否引入了 mockjs,取消掉即可,取消 mock 模式之后,excel 文件打开就不会是乱码了。

 

 

posted @ 2021-07-30 14:56  smil、梵音  阅读(2911)  评论(0编辑  收藏  举报