导读(3行收益):小程序里上传图片最常见的三个问题:原图太大传不上、失败后没有重试、看不到进度用户以为卡死。本文给一套「本地压缩+直传存储+进度重试」的方案,附示例代码和上传检查清单。看完能直接改进你的图片上传功能。
一、上传图片为什么总出问题
三个高频事故:
- 原图太大:手机拍照一张 5-10MB,直接上传要么超时要么被服务器拒绝;
- 失败不重试:网络抖动一下上传中断,用户只能重新拍照再来;
- 没有进度反馈:用户看到一直转圈,以为卡死,直接退出。
根源是把「选图→上传→展示」当成一个同步动作。正确做法是拆三步:选图后先本地压缩,压缩后再直传存储,上传中展示进度、失败自动重试。
二、第一步:本地压缩,别让原图上线
上传前先在本地压缩,减少体积而不是依赖服务器处理:
// 微信小程序:canvas 压缩图片到指定宽度
function compressImage(src, maxWidth = 1280) {
return new Promise((resolve) => {
const ctx = wx.createCanvasContext('compressCanvas');
wx.getImageInfo({
src,
success: (info) => {
const ratio = Math.min(1, maxWidth / info.width);
const w = Math.round(info.width * ratio);
const h = Math.round(info.height * ratio);
ctx.drawImage(src, 0, 0, w, h);
ctx.draw(false, () => {
wx.canvasToTempFilePath({
canvasId: 'compressCanvas',
quality: 0.8, // 质量参数,80% 足够清晰
success: (res) => resolve(res.tempFilePath),
});
});
},
});
});
}
压缩策略:宽度压到 1280px、质量 0.8,一般图片可从几 MB 压到 300KB 左右,兼顾清晰与体积;头像类小图可以更激进(800px、质量 0.7)。注意保留原图的上传成功回显,压缩只影响上传文件,不影响用户本地原图。
两种压缩方案的取舍也要知道:canvas 压缩兼容性最好,各端小程序都支持,适合通用场景;离屏 canvas 或 WebAssembly 压缩性能更好,适合批量多图,但实现复杂度高。绝大多数业务用 canvas 压缩就够了,不要为压缩性能过早引入复杂方案。
三、第二步:直传存储,绕过服务器中转
图片不经过业务服务器转发,直接上传到对象存储,避免服务器带宽与内存被打满:
- 小程序先请求后端拿直传签名(含临时密钥、存储路径、过期时间);
- 小程序带签名直接上传到对象存储;
- 上传成功后把返回的 URL 提交给业务接口记录。
// 上传成功后才把地址交给业务
wx.uploadFile({
url: uploadUrl, // 对象存储直传地址(带签名)
filePath: compressedPath, // 压缩后的本地路径
name: 'file',
success: (res) => {
const fileUrl = JSON.parse(res.data).url;
submitImageUrl(fileUrl); // 回写业务记录
},
});
多图场景的排序与回显也在这里闭环:上传成功后在本地状态数组里记录 URL,按用户选择顺序展示缩略图;上传失败的在列表中保留占位并显示「重试」,用户点重试只重传失败那张,而不是整组重传。这个细节直接影响多图表单(如商品多图、工单附图)的用户体验。
避坑:签名要设置有效期且限制路径前缀(如只允许 images/user/ 目录),防止被利用上传任意文件;直传地址不落业务库,只存最终 URL,减少存储中转。
四、第三步:进度展示与失败重试
上传要有反馈、失败要能重试:
- 进度:
wx.uploadFile的onProgressUpdate实时刷新进度条; - 重试:失败自动重试 2 次(指数退避:1s、3s),仍失败提示「重试」按钮而不是让用户重新拍照;
- 队列:多图上传用队列串行(一次一张),避免并发把带宽打满;
- 失败分类:网络错误可重试,文件损坏/路径无效直接提示更换,避免无意义重试;
- 弱网提示:上传前先检查网络类型(Wi-Fi/4G/弱网),弱网提示用户可能较慢,避免误以为卡死。
五、踩坑清单
- [ ] 原图直传不压缩,几 MB 图片上传超时;
- [ ] 压缩后不保留原图回显,用户看到图片变糊;
- [ ] 图片经服务器中转,带宽内存被打满;
- [ ] 签名不过期/不限制路径,存在被滥用的风险;
- [ ] 上传失败不重试,用户只能重新拍照;
- [ ] 多图并发上传,弱网下全部超时。
六、工程落地建议
图片上传建议按「本地压缩+直传存储+进度重试」三步落地,先覆盖单图再扩展多图队列。若团队没有现成上传链路,可基于成型平台(如乔拓云轻应用)的图片上传能力快速起步,重点核对压缩策略、直传签名与重试机制。
七、复盘清单(可直接抄走)
- [ ] 上传前是否本地压缩并保留原图;
- [ ] 是否直传对象存储、签名是否带有效期且限定路径;
- [ ] 是否有进度反馈与自动重试;
- [ ] 多图是否串行队列上传;
- [ ] 失败后用户能否一键重试而非重新拍照;
- [ ] 多图是否保留占位与单独重试能力。
结语
图片上传的问题大多出在「原图直传+没有反馈」。本地压缩、直传存储、进度重试三步落地,上传从碰运气变成稳定链路。本文仅作技术分享,具体功能以各平台官方实时信息为准。