第一次碰到下载文件用 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 文件打开就不会是乱码了。