前端vue下載文件時blob返回流中怎麼獲取文件名

  我很久之前寫了一篇前端vue利用blob對象下載文件,有些人私信我,如果後端返回流失敗,給出的json對象該怎麼獲得?前端獲取的流怎麼能獲取原文件名?其實在那篇文章之後,我就已經針對這兩個問題進行了優化,於是就有了這篇。

  首先,針對第一個問題,如果能正常獲得文件流,前端則以blob對象承接,反之,一般後端會傳一個json對象告訴你失敗了以及失敗原因,這個時候json對象由於請求中responseType: 'blob'的聲明之後,也會生成文件,但是文件內容是亂碼,這個時候,我們必須要用到FileReader.readAsText():

詳細見MDN官方文檔關於FileReader.readAsText()的描述:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsText。所以上次的代碼經過改造是這樣子的:

<el-button @click="exportExcel()">導出</el-button>

<script>
methods: {
        exportExcel(){
            var params={
                XX:xx//額外需要攜帶的請求體
            }
            this.$axios.get('/XX/XX',{
                params: params,
                responseType: 'blob'   //首先設置responseType字段格式爲 blob
            }).then(res => {
                if(res.type=="application/json"){
                       let reader = new FileReader();
                       reader.onload = e =>this.$alert(JSON.parse(e.target.result).xxxx);   //xxxx爲字段名
                       reader.readerAsText(res);
                }else{
                       let blob = new Blob([res], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"}); // 爲blob設置文件類型,這裏以.xlsx爲例
                       let url = window.URL.createObjectURL(blob); // 創建一個臨時的url指向blob對象
                       let a = document.createElement("a");
                       a.href = url;
                       a.click();
                       // 釋放這個臨時的對象url
                       window.URL.revokeObjectURL(url); 
                   }
             });
        },
     }
</script>      

  然後,我們針對第二個問題,前端獲取的流怎麼能獲取原文件名?有兩種解決方案,都得需要後端同事的配合,一種是在點擊導出按鈕之前,一般這種就是有一個文件列表(表格),前端已經知道文件的位置,然後把文件路徑傳給後端,由後端到指定目錄下取到再傳給你。文件上傳的時候因爲防止文件名重複,後端會對文件進行重命名(採取8位隨機字符串+原文件名),在你知道路徑的情況下,你就可以直接將文件路徑中最後一個"/"後字段進行截取作爲文件名。 

<el-button @click="exportExcel()">導出</el-button>

<script>
methods: {
        exportExcel(){
            var params={
                filePath:this.filePath
            }
            this.$axios.get('/XX/XX',{
                params: params,
                responseType: 'blob'   //首先設置responseType字段格式爲 blob
            }).then(res => {
                if(res.type=="application/json"){
                       let reader = new FileReader();
                       reader.onload = e =>this.$alert(JSON.parse(e.target.result).xxxx);   //xxxx爲字段名
                       reader.readerAsText(res);
                }else{
                       let blob = new Blob([res], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"}); // 爲blob設置文件類型,這裏以.xlsx爲例
                       let url = window.URL.createObjectURL(blob); // 創建一個臨時的url指向blob對象
                       let a = document.createElement("a");
                       a.href = url;
                       let filePath = this.filePath;
                       let subFilePath = filePath.split('/');
                       a.download = subFilePath[subFilePath.length-1].substring(8);
                       a.click();
                       // 釋放這個臨時的對象url
                       window.URL.revokeObjectURL(url); 
                   }
             });
        },
     }
</script> 

  另一種是後端同事先對請求頭進行改造,在給前端返回的請求頭中添加Content-Dispositon字段。

response.reset();
response.setContentType("application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); //設置文件類型,這裏以.xlsx爲例
//設置文件的原文件名,若文件名中含有中文則需要解碼,否則會出現亂碼
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "utf-8"));
// 這步很關鍵,需要在給前端返回的請求頭中添加Content-Disposition字段
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");  

f12控制檯network中請求頭部分

  然後有些人就是在這個地方卡住了,說利用res.headers['content-disposition']取不到Content-Dispositon的值,這是因爲這些人都配置了axios攔截器,而且在攔截器裏寫了相關的處理導致沒有返回全部的響應信息。我們在上面代碼中.then()回調函數中的res返回前是都要經過axios攔截器處理的,如果沒有設置axios攔截器的是可以直接通過res.headers['content-disposition']直接獲取到的。

// 添加響應攔截器
axios.interceptors.response.use(response=>{
    // 對響應數據做點什麼
    return response.data; //這裏只把這個響應裏的data返回回來了,所以取不到headers,想要全部信息就return response;
  }, error=>{
    // 對響應錯誤做點什麼
    return Promise.reject(error);
});

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章