一、背景
近来写了一个react的组件,用来做文件导出。环境是ie10+。
细一点说,就是
1、读取form里的数据
2、向服务端发请求,并下载文件;请求拿到请求状况,假如失足实时反馈给用户。
第一个需求,我们借用了jquery的serializeArray要领,毕竟我们不想再造轮子。那接下来重点说说背面的需求。
二、平常下载文件体式格局
人人在下载的题目的时刻,平常来说,会用到
1、window.open(url);
2、window.location.href = url;
3、iframe,实在与window.open相似,但不必开启新的tab
4、a 标签,应用download属性
这些要领,实在极端依靠服务端的正确性。我们能够看看服务端一旦失足的效果。
1、window.open(url)
翻开一个带毛病信息的页面
2、window.location.href
页面将跳转到一个毛病页面
3、iframe
用户感知不到任何变化
4、a标签
直接涌现 下载失利
固然,假如response header里有content-disposition字段的话,浏览器都邑下载一个带毛病信息的文件。这时刻,实在我们能够多发一个ajax/fetch请求,先检测下接口状况,然后再取做下载逻辑。但如许就对服务器造成了分外的开支。
如许的体验都不太好,作为一个寻求极致体验的顺序猿,我们应当从新思索下,怎样提拔用户体验。
三、浏览器FileAPI体式格局
置信人人对blob这个对象也不太生疏,它是html5规范里的一个二进制数据对象,能够与URL 对象合营,举行文件的下载。
下面是一个最简朴的demo(我们暂时不斟酌浏览器兼容题目)。
let blob2 = new Blob(['123']);
let url = URL.createObjectURL(blob2);
let a = document.createElement('a');
a.download = 'test';
a.href = url;
a.click();
实在如许一个简朴的demo,就能够完成浏览器端本身的下载了。那怎样从服务端拿到数据,并下载呢?
这里,我们拿服务端数据,主如果经由历程fetch,fetch供应了一些api。个中就有一个blob的promise,我们能够把返回的数据转成blob对象,如许就能去下载文件了。
回到最初的需求,我们须要检测接口的状况。实在经由历程fetch,我们完整能够拿到response的信息,既然都能拿到,那控制权就在我们自手上了。
四、分外收成-进度条
根据FileApi的体式格局,我们是一次性从服务端拿到数据,然后再在浏览器端举行操纵。既然是如许,那拿数据的历程是否是就能够显示出进度呢?这个特征,我们用以前传统的下载体式格局是完整做不到的。
关于进度条,我们能够应用fetch合营reader对象来完成进度条功用,以下:
fetch(url).then(response => {
var reader = response.body.getReader();
var headers = response.headers;
var totalLength = headers.get('Content-Length');
var bytesReceived = 0;
reader.read().then(function processResult(result) {
if (result.done) {
return;
}
bytesReceived += result.value.length;
console.log(`progress: ${bytesReceived / totalLength * 100}%`);
return reader.read().then(processResult);
});
});
固然,有人能够会说ie下fetch会有题目。没错,确切会有题目,但这时刻我们能够用XMLHttpRequest这个对象来完成,会更简朴直接一点。
五、常见题目
1、filename
经由历程fileapi的体式格局下载文件,有个很主要的题目,就是文件名。最初的一些下载体式格局,都是浏览器本身经由历程推断content-disposition这个字段来读取文件名。那如今不一样了,我们须要本身来读取文件名,这时刻不免要本身读这个header,经由历程正则婚配下文件名。
2、cors
关于cors题目,实在只如果异步请求,都邑遇到。新版浏览器,我们经常运用access-control-allow-origin这个字段来处置惩罚跨域题目。这时刻,我们在读文件名的能够要留一点,记得在header里加上Access-Control-Expose-Headers这个字段,不然fetch是取不到filename信息的。详细能够看看这篇doc
3、大文件下载题目
在用fileapi的时刻,我们发明文件过大会让浏览器崩溃,会致使文件下载失利。现在我在测试500mb以上的文件的时刻就会遇到如许的状况。这个题目,能够经由历程webkitrequestfilesystem这个对象来曲线处置惩罚,但这并非一个standard api,现在只要新版chrome支撑这个对象,所以只管不要去用。
我们推荐在拿到response的时刻,读取一下blob的size,假如发明太大,就举行降级处置惩罚,运用我们最初的那中体式格局。
五、总结
我一向置信no silver bullet这句话,虽然fileapi这类体式格局能处置惩罚部份题目,但实在也有许多瑕玷,置信人人会在现实场景中会更深入的感受到。所以在设想组件的时刻,我们在做好文雅降级的计划同时,还特意为人人开放了种种下载体式格局,以顺应种种场景。