前端下载后端返回文件流【踩坑篇】

1,872 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情

事情是这样的,我们pass平台资源面板在对接其他项目组导出文件功能,我们这边直接Node端转发他们的接口,接收到返回的包文件,直接返给前端,前端做下载。

问题

返回的包文件流五花八门

  • 第一种 企业微信截图_16722314128130.png
  • 第二种 image.png

说实话,之前很少接触过下载文件流这类的工作,这次掉坑里了!

网上找各种解决方案,最常见的就是获取到文件流,然后模拟< a >标签点击事件来下载对应文件,代码大多如下:

const blob = new Blob([data.maxDownload.data], {
    type: 'application/octet-stream',
});
let n = document.createElement("a");
n.setAttribute("href", window.URL.createObjectURL(blob));
n.setAttribute("download", $(dom).attr('data-name')+'.zip');
n.style.display = "none";
document.body.appendChild(n);
n.click();
document.body.removeChild(n);

但是问题来了,为啥怎么下载,文件解压之后里面都是空?

image.png

image.png

下面让我们解决问题:

解决方案

1.前端直接fetch请求

ok因为返回的是文件流,我们只接fetch转blob执行:

return fetch("https://***.***.cn/model/download/".concat(e, "/ceshi"), {
    responseType: "blob", // 返回blob,不写没关系
    headers: {
        Authorization: "Bearer ".concat(token)
    },
    method: "GET"
})
.then((function(e) {
    console.log(e,"返回的的文件流")
    e.blob().then((function(e) {
        console.log(e,"执行blob方法之后")
        var i = document.createElement("a")
            , o = document.querySelector("body");
        i.href = window.URL.createObjectURL(e),
        i.download = $(dom).attr('data-name')+'.zip',
        i.style.display = "none",
        o.appendChild(i),
        i.click(),
        o.removeChild(i),
        window.URL.revokeObjectURL(i.href)
    })).catch((function(e) {

    }))
}))

image.png

2.node端接受转发的文件流

// node端做base64位转换,返回给前端
return {
    maxDownload: new Buffer(maxDownload.getBody()).toString('base64')
}
// 前端模拟a标签触发,下载文件
const n = document.createElement("a");
n.setAttribute("href", "data:text/plain;base64,"+ data.maxDownload);
n.setAttribute("download", 'ceshi.zip');
n.style.display = "none";
document.body.appendChild(n);
n.click();
document.body.removeChild(n);

总结

上面两个解决方案都解决了我遇到的问题,为了防止接口暴露,所以只能在Node转发,其实一开始我一直以为问题出在了文档流类型上了,认为只要 a 标签加载正确的文件流类型,文件就可以正确下载(不确定可行,没试出来),后来切换了别的思路,也算曲线解决了问题。

水平有限,还不能写到尽善尽美,希望大家多多交流,跟春野一同进步!!!