浏览器端下载那些事

一、背景

近来写了一个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这类体式格局能处置惩罚部份题目,但实在也有许多瑕玷,置信人人会在现实场景中会更深入的感受到。所以在设想组件的时刻,我们在做好文雅降级的计划同时,还特意为人人开放了种种下载体式格局,以顺应种种场景。

    原文作者:hirra
    原文地址: https://segmentfault.com/a/1190000005125573
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞