关于uniapp下载文件遇见的坑及总结

===============【需求:在小程序中将后端返回的字节流写入文件并转发】==============

==============【中间一堆是记录走的弯路,可跳过,最后两段代码是最终结果】==========

背景:服务器将生成的文件二进制流返回给前端,(即服务器写入本地文件,需要下载时读文件内容并通过response 的 outputStream返回给前端)
原需求:仅有网页版,采用构造<a href=''>的方式通过浏览器下载,体验很好,网上文章很多,不做赘述。

后续需求:要求做个app或小程序,方便客户使用,经过尝试,上述<a >的方式不再适用,效果如下(该方法并不规范,是通过将网页版程序build 后的 dist文件 放进5+App中运行出来的),解决未果

第二次尝试:创建uni-app项目,使用uni.downloadFile接口,该方法下载之后,日志提示下载成功,但通过返回路径再进行 uni.saveFile, 报路径不存在。将路径打印出来检查发现确实不存在,很迷。经过百度发现以下方法可以成功:

export function createFlie(fileName, data) {
  return new Promise(resolve => {//这里封装了个是一个promise异步请求
    // plus.io.requestFileSystem是请求本地文件系统对象
    plus.io.requestFileSystem(
    	plus.io.PUBLIC_DOCUMENTS, // 文件系统中的根目录下的DOCUMENTS目录
    	fs => {
    		// 创建或打开文件, fs.root是根目录操作对象,直接fs表示当前操作对象
    		fs.root.getFile(fileName, {
    			create: true // 文件不存在则创建
    		}, fileEntry => {
    			// 文件在手机中的路径
    			console.log(fileEntry.fullPath)
    			fileEntry.createWriter(writer => {
    				// 写入文件成功完成的回调函数
    				writer.onwrite = e => {
    					console.log("写入本地文件成功");
						resolve("写入本地文件")
    				};
    				// 写入数据
    				writer.write(JSON.stringify(data));
    			})
    		}, e => {
    			console.log("getFile failed: " + e.message);
    		});
    	},
    	e => {
    		console.log(e.message);
    	}
    );
  })
}

第三次尝试:由于做 ios app太麻烦,放弃,转战小程序。注意:坑又来了,上述方法仅适用于app,因为plus是安卓和ios的增强类,在小程序中会报 “plus 未定义”。换 wx.downloadFile 接口,微信文档:网络 / 下载 / wx.downloadFile (qq.com)
贴出数据处理部分:

uni.request({
	url: `${BASE_URI}/products/download-lk`,
	method: 'POST',
	data: frmIds,
	header: {
		'content-type': 'application/json',
		'Authorization': 'Bearer ' + wx.getStorageSync('token')
		},
	responseType: 'arraybuffer',
	success: (res2) => {
		if (res2.data instanceof ArrayBuffer) {
		    // createFlie(fileName, res.data)
		    var url_file = wx.createBufferURL(new Uint8Array(res2.data))
		    //writeFile(fileName, url_file)
		    dowloadFile(fileName, url_file)
	    }
	},
	fail(err) {
		console.log(err)
	}
})
export function dowloadFile(fileName, url_file) {
	var path = `${wx.env.USER_DATA_PATH}/` + fileName
	console.log('url: ', url_file)
	wx.downloadFile({
		url: url_file,
		filePath: path,
		success(res) {
		  console.log("成功:", res)
			uni.showModal({
				title: '下载成功',
				content:'是否分享该文件',
				showCancel: true,
				success: function(res) {
					if (res.confirm){
						wx.shareFileMessage({
							filePath: path,
							success() {
								console.log("分享成功")
							},
							fail(err) {
								console.log("分享失败: ", err)
							}
						})
					}
				}
			})
		},
		fail(err) {
			console.log(err)
		}
	})
}

在小程序调试中该方法可以正常下载,不出意外的话就不会出意外,发布体验版测试,该来的它还是来了,protocol must be http or https

打印出来看一下,小程序开发工具里,是http

真机调试中

这个问题我没有去深究,采用备选方案:自己写入文件,但如果直接将resData写入,下载的文件大小是不对的

终极解决方案它来了:先读再写
文档:文件 / FileSystemManager / FileSystemManager.readFile (qq.com)

export function writeFile(fileName, resData) {
	var path = `${wx.env.USER_DATA_PATH}/` + fileName
	console.log("wx path: ", path)
	const fs = wx.getFileSystemManager()
	fs.readFile({
		filePath: resData,
		success(res) {
			console.log("文件读取成功")
			fs.writeFile({
			  filePath: path,
			  data: res.data,
			  success(res) {
			    console.log("成功:", res)
				uni.showModal({
					title: '下载成功',
					content:'是否分享该文件',
					showCancel: true,
					success: function(res) {
						if (res.confirm){
							wx.shareFileMessage({
								filePath: path,
								success() {
									console.log("分享成功")
								},
								fail(err) {
									console.log("分享失败: ", err)
								}
							})
						}
					}
				})
			  },
			  fail(res) {
			    console.error("失败: ", res)
			  }
			})
		},
		fail(err) {
			console.log(err)
		}
	})
}

最后终于成功拿到了文件并解析成功,中间还经历了文件内容处理的坎坷,我这个文件是二进制格式的,处理方法都在上面的代码里了

后续:读写的方法,在安卓上可以下载成功,ios上不行

==============================【最终结果】=================================


后经过调整发现走了弯路,最终解决方案,获取到buffer,直接写,真机调试安卓,ios均可用

uni.request({
				url: `${BASE_URI}/products/download-lk`,
				method: 'POST',
				data: frmIds,
				header: {
					'content-type': 'application/json',
					'Authorization': 'Bearer ' + wx.getStorageSync('token')
				},
				responseType: 'arraybuffer',
				success: (res2) => {
					if (res2.data instanceof ArrayBuffer) {
						var url_file = wx.createBufferURL(new Uint8Array(res2.data))
						writeFile(fileName, new Uint8Array(res2.data).buffer)
					}
				},
				fail(err) {
					console.log(err)
				}
			})
export function writeFile(fileName: string, data: ArrayBuffer) {
	var path = `${wx.env.USER_DATA_PATH}/` + fileName
	console.log("wx path: ", path)
	const fs = wx.getFileSystemManager()
	fs.writeFile({
		filePath: path,
		data: data,
		success(res) {
			shareFile(path) //调用 wx.shareFileMessage
		},
		fail(res) {
			wx.showToast({
				title: '下载失败',
				icon: 'error'
			})
			console.error("写入文件失败: ", res)
		}
	})
}

### UniApp 小程序 文件流 上传 图片 实现方法 在 UniApp 中通过文件流的方式上传图片涉及到几个主要步骤,包括选择图片、读取图片作为数据流以及发送请求给服务器。以下是具体实现的方法: #### 使用 `uni.chooseImage` 方法选取图片 为了允许用户从相册或相机中选择图片,可以调用 `uni.chooseImage(OBJECT)` 函数来获取所选图像的信息。此函数返回的对象包含了本地临时路径和其他属性[^1]。 ```javascript // 调用 chooseImage 接口选择一张或多张图片 uni.chooseImage({ count: 1, // 默认9 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function (res) { const tempFilePaths = res.tempFilePaths; console.log('Selected image path:', tempFilePaths); // 进一步处理选定的图片... } }); ``` #### 创建 FormData 对象并加入图片文件 一旦获得了图片的临时路径之后,就需要创建一个 `FormData` 对象并将该对象用于封装要上传的数据。对于每一条记录来说,应该把对应的文件添加进去以便后续提交至服务器端。 ```javascript let formData = new FormData(); formData.append("file", {uri:tempFilePaths[0], name:"image.png", type:"image/png"}); ``` 需要注意的是,在某些情况下可能还需要设置额外参数比如文件名称 (`name`) 和 MIME 类型 (`type`) 来满足特定的服务端需求。 #### 发送 POST 请求携带二进制数据 最后一步就是利用合适的 HTTP 库(例如 axios 或者 fetch API),向目标 URL 地址发起带有上述构建好的表单数据体的 POST 请求。这里假设服务端已经配置好接收 multipart/form-data 形式的请求,并能够解析其中包含的文件内容。 ```javascript fetch('/upload-endpoint-url', { method: 'POST', body: formData, }).then(response => response.json()) .then(data => { console.log('Upload successful!', data); }).catch((error) => { console.error('Error during upload:', error.message); }); ``` 以上就是在 UniApp 小程序里采用文件流传输模式完成图片上载的过程概述[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值