第一次碰到下載文件用 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 文件打開就不會是亂碼了。