背景
微信小程序给开发者提供了downloadFile的api进行下载操作,可是最近公司项目遇到在苹果手机上调该接口下载文件时报file data is empty失败信息。最后使用arraybuffer解决了这个问题。
downloadFile
官方下载接口downloadFile,传入对应参数,成功的话,就会返回文件保存的路径,不需要像在浏览器环境下使用blob,fileReader等来处理。
提示:官方会根据响应的
content-type来处理文件类型。如果只是简单的application/octet-stream,在开发工具上是bin后缀,而在真机上是unknow后缀
自定义下载
基本实现思路是,使用request请求,响应的数据类型responseType为arraybuffer,再使用小程序文件管理器FileSystemManager以binary方式保存文件。
const imgUrl = 'http://attach.bbs.miui.com/forum/201306/23/110328s72xxse7lfis9fnd.jpg';
wx.request({
url: imgUrl,
responseType: 'arrayBuffer',
success: (res) => {
const { data } = res;
const fs = wx.getFileSystemManager();
const filePath = wx.env.USER_DATA_PATH + '/temp.jpg';
fs.writeFile({
filePath,
data,
encoding: 'binary',
success: () => {
this.setData({
imgPath: filePath,
})
}
});
}
});
找张网络图片测试,实现代码大体如上。但是这个没有考虑下载失败,处理文件后缀等情况。所以接下来封装个比较实用公共的方法。
提示:在开发工具上测试时,勾选不校验合法域名
封装公共方法
const downloadFile = function(url, data, path) {
let filePath = '';
wx.showLoading({
title: '下载中...',
mask: true,
});
return new Promise((resolve, reject) => {
wx.pro.request({
url,
data,
responseType: 'arraybuffer',
}).then(res => {
console.log(res);
const contentType = res.header['Content-Type'];
// 根据content-type: application/json 来判断成功,还是后台的错误提示
const isErrTips = contentType.includes('application/json');
if (isErrTips) {
// 将arraybuffer转为字符串
const tips = ab2Str(res.data);
reject(tips);
}
// 没有指定保存路径时,使用时间戳生成
const fileFormat = contentType.includes('application/octet-stream') ? 'bin' : contentType.split('application/')[1].split(';')[0];
filePath = path || (wx.env.USER_DATA_PATH + '/' + Date.now() + '.' + fileFormat);
// 保存文件
return wx.fsPro.writeFile({
filePath: filePath,
data: res.data,
encoding: 'binary',
});
}).then(() => {
wx.hideLoading();
// 成功后,返回保存的文件路径
resolve(filePath);
}).catch(err => {
wx.hideLoading();
reject(err);
});
});
};
调用处代码
const imgUrl = 'http://attach.bbs.miui.com/forum/201306/23/110328s72xxse7lfis9fnd.jpg';
downloadFile(imgUrl).then(res => {
console.log(res);
// 拿到保存的路径,进行业务操作
this.setData({
imgPath: res,
});
}).catch(err => {
console.log(err);
});
公共方法简单封装了请求,保存文件的功能,最后返回文件路径,基本和官方提供的downloadFile的功能一致,但是进一步处理了后台响应错误时的处理,demo里将微信api转为Promise对象了,所以可以链式调用。
注意的是,保存的文件在小程序提供的用户目录下,最大10m,所以不用的时候,手动删掉。downloadFile默认文件保存在临时目录下,微信会找时机清理。详看小程序文件系统
处理后台返回的异常的另外一种思路就是,可以像官方downloadFile一样,不管结果如何,都将结果保存为一个文件,最后使用FileSystemManager.readFile来读取文件内容,encoding为utf8。
- 下载成功

- 后台返回错误提示

结语
本文主要介绍了如何使用普通wx.request接口,来实现下载文件的功能。主要可以用在:
- 调用官方downloadFile在一些机型出现意外的情况,毕竟我们没有微信小程序底层源码,定位不了具体问题,在官方还没解决时,可以使用这个"曲线救国"的解决方法
- 官方downloadFile会根据响应的conten-type来处理文件类型,但是后台所有文件流都是application/octet-stream,使用文中方法,如果知道返回类型,可以提前设置好路径及文件后缀
- 下载文件时,后台返回错误提示,文中方法比较人性化的处理了,并不是所有结果都保存为文件
不足的地方是:
- 文件要保存在微信提供的用户目录下,需要手动删除,不能像官方downloadFile保存在临时目录下,不需要手动清理,这个不足也是没法避免的。