前端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);
});

 

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