Vue2.x从后端获取流数据并保存为Excel、CSV或其它格式下载
一、问题
- 后端返回的是数据流,前端需要将数据导出成为Excel文件进行下载
二、解决
-
首先判断请求类型,以post请求为例,需要在二次封装axios中设置
responseType
值的类型为blob
,之后将封装好的请求挂载到Vue
实例对象身上,我在man.js
中进行的挂载,挂载后的请求方式名称也就是后文的$postExcel
export async function $_post_excel(url, obj = {}) { /* request payload */ return await axios({ method: "post", url: url, responseType: 'blob', // 请求为blob类型 headers: { 'session': "", "Content-Type": "application/json; charset=UTF-8" }, transformRequest: [ function (data) { return data; } ], data: obj }).then(res => { return res.data }) }
- 其中
responseType
的取值范围如下:
- 其中
-
配置好取值后,请求后端接口,发现此时接收到的值是一个
blob
对象,blob
对象可以看作是存放二进制数据的容器,可以看到后端已经将该文件类型的type
进行了配置,限制为excel
的形式;
-
最后通过创建a标签的形式进行文件的下载即可,代码如下:
// 导出excel表 async putoutTeam() { const res = await this.$postExcel(`${this.$url}/src/request_url_in_here`) let fileName = 'Excel表模板.xlsx' // xlsx和xls都是支持的 // 通过创建a标签实现文件下载 let link = document.createElement('a') link.download = fileName link.style.display = 'none' link.href = URL.createObjectURL(res) document.body.appendChild(link) link.click() URL.revokeObjectURL(link.href) // 释放URL 对象 document.body.removeChild(link) }
-
注意:因为文件类型
type
后端进行了配置,所以前端不需要过多处理,如果没有配置需要进行转换,以上代码基础上进行增加和更改:const blob = new Blob([res], { type: 'application/x-excel,charset=UTF-8' }) // 配置blob的type const blob = new Blob([接收的blob对象], { type: 'text/csv,charset=UTF-8'}); // 如果是csv文件使用这个配置,上述的文件名fileName也需要修改,加上UTF-8防止中文乱码 link.href = URL.createObjectURL(blob) // 此处也需要更换为新建的blob实例对象
三、扩展(文件名携带在响应头中)
-
如果文件名由后端规定,并且将文件名携带在响应头中传递过来,前端需要对响应头进行处理后对文件进行命名,修改上述的
axios
请求如下,也就是将响应的res.data
改为res
,res
中包含有响应头的信息:export async function $_post_excel(url, obj = {}) { /* request payload */ return await axios({ method: "post", url: url, responseType: 'blob', // 请求为blob类型 headers: { 'session': "", "Content-Type": "application/json" }, transformRequest: [ function (data) { return data; } ], data: obj }).then(res => { return res }) }
-
之后打印出响应的
res
信息,所需要的文件名信息包含在res.headers
的content-disposition
中,存在filename
也就是文件名,这里只需要截取文件名展示即可:// 导出excel表 async putoutTeam() { const res = await this.$postExcel(`${this.$url}/src`) // 做一层防护,防止没有不存在content-disposition导致报错 if (res.headers["content-disposition"]) { // 截取名字,这里中文会乱码 let temp = res.headers["content-disposition"].split(";")[1].split("filename=")[1] // 解码URI中被转义的字符,解决中文乱码 let fileName = decodeURIComponent(temp) // 通过创建a标签实现文件下载 let link = document.createElement('a') link.download = fileName link.style.display = 'none' // 这里改为res.data,流数据存在data中 link.href = URL.createObjectURL(res.data) document.body.appendChild(link) link.click() URL.revokeObjectURL(link.href) // 释放URL 对象 document.body.removeChild(link) } else{ return } }
到这里问题就解决了,有更好的方法欢迎留言评论🌈