聊聊uniapp进行微信小程序开发时大文件图片上传的爬坑经历

方滴云WEB2023-05-20 17:18

项目背景

近期,我们有一个多端项目的开发,为了降低开发成本,小程序端与APP端的开发,我们选择使用uniapp进行,必竟很多地方的样式相似,且逻辑基本一致,配合uniapp灵活的条件编译,各种不平,都很迅速的平了。

常在河边走,哪有不湿鞋。各种各样的问题,该面临的,一个都逃不掉,它总会在这儿或者哪儿,以逸待劳的候着您,当您觉得一切都OK了的时候,它会选择静静的站出来。

面临问题

本次的核心问题,还是大文件上传,与上次讨论过的还是有点不一样。上期解决的是通用类大文件云端上传,由之前的前端分片后端合成,变成使用腾讯云COS的高级上传接口进行智能分片上传。此次大文件上传核心解决的是图片类文件。

问题二,微信小程序中,很多之前H5端或APP端的接口不支持,要使用画面提供的接口来替换。

问题三,画布通过canvasToTempFilePath后生成的体积比压缩前还大,设置quality参数无效,这是今天最大的坑了。

解决思路

首先,我们统一上传接口,不管是大文件图片,还是普通图片,我们一视同仁,前端一个上传函数,后端一个上传接口,内部流程上的不同通过参数了解决它。

大体积图片我们的解决思路是,当图片的体积超过某一个设定值,比如512KB时,我们获取图片的长宽,然后根据设定的最大长宽积,比如1600*1600,设置一个画布,再把这个图片放到画布上,最后将这个画布传到云端或服务器端。

解决过程

首先文件上传方面我们用到的接口是uni.uploadFile(),它的参数还是比较简单的,如下图所示,我们把要注意的参数列出来了。

在APP端,前期我们是把画布转成文件进行上传的,所有使用到了这里的files。下面我们重点来看下小程序的那个坑,以及我们的解决方案。

首先,用户通过uni.chooseImage()接口,可能拿到图片的基本信息,如大小,本地路径等,接下来我们通过大小来判读是否要压缩图片,如果要压缩我们再通过uni.getImageInfo()来获取图片基本信息,进行后续 的操作。

通过uni.chooseImage()后就走到了我们的的统一上传接口fdyModel.toUploadFile()中了。

这个接口很简单,必要的参数传入后,通过cb这个回调,把处理的结果返回给调用方。下面我们首先来看下压缩的部分。

这里的imgMaxPx是我们定义的一个常量,就是最大的长或宽的尺寸。接下来我们看APP端的处理。

let img=new Image(),canvas=document.createElement('canvas');
let ctx=canvas.getContext('2d')
img.src=res.path;

下面我们再看来微信小程序的处理,首先我们这里使用到了创建离屏 canvas 实例,文档地址如下:https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.createOffscreenCanvas.html

通过如上操作,我们就将压缩后尺寸的图片放到画布的了,后续我们就是进行服务端的上传了,这里的上传有两种解决方案,第一种是通过uni.canvasToTempFilePath(),拿到画面生成的本地临时链接。

大概是上面的样子,但是这里有个大坑,全网都在反应这个canvasToTempFilePath生成的图片体积很大,通过传quality是无效的。或许若干天或若干年后,这个问题可以被解决的。

劳动人民,不能停止劳动,更不可以停止思考,于是,我不小心在微信小程序的文档中看到了canvas.toDataURL()这个API。

这个接口返回的,就是画布的base64,最主要的是这个地方的图片质量设置是有效的。于是有了下面的解决方案,也APP的效果一致。

值得注意的是,关于base64的上传,我们其实走的是uni.request()的POST请求。当然这个我们在服务端也是做了处理的。

至此,完美解决了!

补充:APP端问题比较多。