前言:基于vue2+element-ui的一个后台管理系统,需求评审要加一个导入导出文件的功能,由于可能导出的数据量过大(几十万条数据),下载时间过长,所以用.zip压缩文件替代excel文件
本人以前也做过导出文件的功能,但是用的方法是后端处理数据然后放到另一个服务器上,前端要做的就是window.open 打开这个默认地址加返回的地址拼接成的链接就可以自动下载了
但是现在新入职的这家公司后端老哥明确告诉我:不行!没办法了,百度csdn chatgpt搜吧。。。。
经过一堆无用答案和无数的坑后终于有了解决办法,参考https://blog.csdn.net/Amy126/article/details/113882421 老哥和其他各种老哥的方法
总结:1.在接口处设置responseType和headers:
export function searchPersonnelHousInfoExport(query) {
return request({
baseUrl: '/api-login',
url: '/miniadmin/personnelHous/searchPersonnelHousInfoExport',
method: 'GET',
params: query,
responseType: 'blob', //注意
headers: { //注意
'Content-Type': 'application/json; application/octet-stream'
}
})
}
2.调用接口(注意设置文件格式)
async exportex(){
let postData = {
current: this.currentPage,
size: this.pageSize
}
let res = await searchPersonnelHousInfoExport(postData)
let blob = new Blob([res.data], { type: 'application/zip' }); //设置下载的内容以及格式
const url = window.URL.createObjectURL(blob); //设置路径
const link = window.document.createElement('a'); // 创建a标签
link.href = url;
let filename = res.headers['content-disposition']
.split(';')[1]
.split('filename=')[1]
let decodedURL = decodeURIComponent(filename); //解码,返回的是文件流所以我从res.header里面拿的文件名,但是是编码后的?巴拉巴拉的,所以拿来用的话要在前端解码
link.download = decodedURL; //设置文件名
link.style.display = 'none';
link.click();
console.log(link,'res')
URL.revokeObjectURL(url);
}
3.如果下载下来是一堆乱码或解析不了文件,去看看是否在main.js引入了mockjs,非必要就不引入,如果确实需要就这样:
————————————————————分割线————————————————————
摸索过程(出现各种问题的原因,时间着急的同学可以跳过):新入职的这个公司没弄过这个东西,所以就得自己下载处理接口返回的文件流,也就是那“一堆乱码”,当时打印res发现res.header里有一个地址,打开发现能直接下载这个压缩文件,心里暗暗窃喜,这不是省事了吗,结果清空筛选条件发现是后端放开了对token的校验,一旦恢复校验接口马上就报错了,而实际线上环境这样做显然是不安全的,不可能让后端放开校验,而出现这种情况的原因是在原页面发了一次请求,打开新页面又发了一次请求,原页面在请求头中设置了token,新开的页面哪有这个东西,着急坏了,想着能不能把token跟着参数一起传过去,后端校验找不到请求头中的token去判断参数里有没有token,后端的回答是:所有请求都要先校验有无token!!!
这就很麻烦了,老老实实处理流吧QAQ
各种查各种找,经过很多无用尝试(当磨炼心态了)结果得出的结论:
步骤1:
接口代码(注意设置responseType和headers):
export function searchPersonnelHousInfoExport(query) {
return request({
baseUrl: '/api-login',
url: '/miniadmin/personnelHous/searchPersonnelHousInfoExport',
method: 'GET',
params: query,
responseType: 'blob', //注意
headers: { //注意
'Content-Type': 'application/json; application/octet-stream'
}
})
}
步骤2:
调用接口:
async exportex(){
let postData = {
current: this.currentPage,
size: this.pageSize
}
let res = await searchPersonnelHousInfoExport(postData)
let blob = new Blob([res.data], { type: 'application/zip' }); //设置下载的内容以及格式
const url = window.URL.createObjectURL(blob); //设置路径
const link = window.document.createElement('a'); // 创建a标签
link.href = url;
let filename = res.headers['content-disposition']
.split(';')[1]
.split('filename=')[1]
let decodedURL = decodeURIComponent(filename); //解码,返回的是文件流所以我从res.header里面拿的文件名,但是是编码后的?巴拉巴拉的,所以拿来用的话要在前端解码
link.download = decodedURL; //设置文件名
link.style.display = 'none';
link.click();
console.log(link,'res')
URL.revokeObjectURL(url);
}
结果:真的下载到了.zip压缩文件了!兴高采烈的打开,结果傻眼了:能拿到压缩文件,解压后却不是excel文件,当时我的心,拔凉拔凉的啊,但是这边排期还有不到两天了,没办法,搜解决办法吧
。。。。。漫长的一天多。。。。。。
终于在搜的头晕眼花口吐白沫甚至想到iframe嵌套往里塞地址和请求头之后找到了一个不一样的结论:mock模块会影响原生的ajax请求,使得服务器返回的blob类型变成乱码
瞬间虎躯一震,来到main.js一看:
// 全局 Mock 接口
import './mock'
赶紧试试,立马把引入注释了:
我滴妈啊,终于解决了,当时热泪盈眶,因为这个乱码问题困扰我一天半了,mock火速滚出我的电脑!