工作总结(10) - 处理文件流

这篇工作总结将整理一下如何处理文件流。

  • 图片blob对象转为本地地址

一般图片blob对象转为本地地址的需求场景是需要后端生成一个二维码,一般返回是一个blob对象,然后前端需要通过这个blob对象生成一张图片展示出来。

这个实现的方案比较简单,主要依靠web API URL.createObjectURL()。所以首先需要判断浏览器是否支持URL.createObjectURL()方法。

发请求的时候,因为需要后端返回一个blob类型,所以请求头需要设置responseTypeblob,返回就是blob对象。

然后调用URL.createObjectURL()方法,把blob对象传入,这个方法将创建并返回一个URL对象,这个url就可以用于页面上图片的显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 这里使用axios来演示
if (window.URL.createObjectURL) {
this.axios.post(api, {
url: url
}, {
responseType: 'blob'
}).then(response => {
let url = window.URL.createObjectURL(response.data)
// ...
})
} else {
// ...
}

不过MDN上有提示到如果不需要这些URL对象的时候,最好通过URL.revokeObjectURL()方法来释放掉,虽然浏览器在document卸载的时候会自动释放这些URL对象。这个情况需要根据业务需要进行处理了。

  • 文档blob对象转为文档文件下载

处理文档blob对象转文档文件也是要涉及到图片blob对象转图片地址的处理,不过因为文档文件的格式各有不同,下载的文件还有文件名,而且转出来的文档文件还需要实现下载,所以实现的步骤就比较多。

首先,发请求的时候仍然需要按照上述请求图片blob对象一样,请求头需要设置responseTypeblob

1
2
3
4
5
6
7
8
9
10
11
12
// 这里使用axios来演示
if (window.URL.createObjectURL) {
this.axios.post(api, {
url: url
}, {
responseType: 'blob'
}).then(response => {
// ...
})
} else {
// ...
}

响应返回之后,响应头中有一个值需要用到,Content-DispositionContent-Disposition中提供了文件的默认文件名,一般格式为attachment;filename=FileName.txt。所以我们需要先获取到文件的文件名:

1
2
3
4
5
6
let fileName = res.headers['content-disposition'].split(';')[1].split('=')[1];
// 如果涉及到文件名为中文,以上代码最后得到的字符串可能是一串乱码,所以才要再做一步处理
// decodeURIComponent方法传入一个编码后的部分URI,返回一个解码后URI字符串
// escape方法可以生成新的由十六进制转义序列替换的字符串,但方法已经被Web标准废弃,MDN建议使用 encodeURI 或 encodeURIComponent 代替
// decodeURI方法返回一个给定编码统一资源标识符(URI)的未编码版本的新字符串
fileName = decodeURI(escape(decodeURIComponent(fileName)));

下一步就是要把blob对象转化为文档文件。因为不同文件的文件类型不同,如果返回的blob对象的文档类型不是对应的文件类型(可以通过blob对象中的type或者响应头的Content-Type获得),则需要把blob对象先转为对应文件类型的blob对象,然后调用URL.createObjectURL()

1
2
// 这是转为xlxs格式,'application/vnd.ms-excel;charset=utf-8'是xlxs的固定写法
let url = window.URL.createObjectURL(new Blob([res.data], {type: 'application/vnd.ms-excel;charset=utf-8'}));

因为还要实现自动下载,所以可以生成一个a标签,link属性指向上述生成的url,然后js控制点击,就可以实现下载:

1
2
3
4
5
6
let link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();

完整代码就不贴了,基本实现流程就是这样。