首页 前端知识 前端调接口下载(导出)后端返回.zip压缩文件流(的坑!)

前端调接口下载(导出)后端返回.zip压缩文件流(的坑!)

2024-04-08 11:04:01 前端知识 前端哥 337 569 我要收藏

前言:基于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火速滚出我的电脑!

转载请注明出处或者链接地址:https://www.qianduange.cn//article/4569.html
标签
评论
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!