距离上次博文更新已经快一个月了,期间忙于各种事情无法脱身。今天难得闲暇 and then 就来更新啦…
上篇中我们了解了下载React中如何实现文件的上传,虽然不算什么高大上的技术但实际开发的时候会让自己更加的游刃有余。今天继续更新另一个相关的技术 –> 文件的下载
看过上篇博文的朋友应该有印象,做文件上传的功能可以用Form表单
、fetch
(Ajax或者Axios都行)和Form+fetch
这三个方法。后台采用express框架,由于fetch请求会涉及到跨域问题,所以后台还使用了Cors中间件来解决跨域的问题。这一点在上篇博文中都有提及所以在这里就不加赘述。
本篇所说的文件下载也是基于Form
和fetch
(Ajax或者Axios都行)。且听慢慢道来…
Form
Form表单可谓是前端界的万金油,什么数据提交、上传下载都样样精通,最关键的是:不需要考虑跨域
。
利用Form表单进行文件下载很简单,只需要几行代码就可以搞定:
class FormDownload extends Component {
render() {
return (
<form method="get" action="http(s)://下载文件的后台接口">
<button type="submit">Download!</button>
</form>
)
}
}
export default FormDownload;
只要这一小段代码就可以实现文件的下载,是不是很开森?
Fetch
利用Fetch实现文件下载相比于Form那就显得很麻烦也很啰嗦,为什么呢?上代码先
class FetchDownload extends Component {
download = () => {
fetch('http(s)://下载文件的后台接口').then(res => res.blob().then(blob => {
let a = document.createElement('a');
let url = window.URL.createObjectURL(blob);
let filename = res.headers.get('Content-Disposition');
if (filename) {
filename = filename.match(/\"(.*)\"/)[1]; //提取文件名
a.href = url;
a.download = filename; //给下载下来的文件起个名字
a.click();
window.URL.revokeObjectURL(url);
a = null;
}
}));
};
render() {
return (
<input type="button" value="下载" onClick={this.download}/>
)
}
}
export default FetchDownload;
麻烦在哪儿:
1、需要考虑跨域问题
2、需要对返回值进行转化
3、需要有DOM操作(生成a标签和销毁a标签)
下面就一起来看看具体操作步骤:
- 用fetch访问后台接口并接受后台返回值。因为fetch方法返回一个Promise对象,因此我们可以在then用获取到它的返回值
- 这一步就厉害了。fetch的返回值是一个
有意思的对象
,它包含了很多方法,其中一个方法就是blob()。这个方法可以将fetch的返回值转化成Blob对象。 - 利用
document.createElement
创建一个a
标签 - 利用
window.URL.createObjectURL
将blob数据转成对应url
。 - 通过fetch的响应头获取到文件名
res.headers.get('Content-Disposition')
。这里需要mark下,因为我们后台使用了Cors中间件来解决跨域问题,因此需要做特别的设置来让Cors将响应头给暴露出来'exposedHeaders': '*'
,具体的大家可以看后台代码。 - 接下来就是对a标签的一系列操作,然后模拟点击事件触发下载动作。
- 最后需要将转化出来的url进行销毁
window.URL.revokeObjectURL(url)
,a标签置为null
看完整个过程,除了了解到前面所说的麻烦
,我们依然要看到其优点所在。对于Form实现的下载功能,我们只能
做下载,而不能做额外
的事情;但是使用fetch我们可以将获取到的数据做更多的处理,自由度相对较高。
总结
目前这方面的轮子特别多而且很是花里胡哨(但是用的特别爽,真香系列!),不过最基础的往往也就这么点技术。万丈高楼平地起,学好基础何怕不会造轮子。。。哈哈。另外再把demo贴一下,有兴趣的同学可以下载下来跑一下溜溜