UniApp文件上传大小限制问题解决方案
问题背景
最近在开发一个基于UniApp的wgt项目(小程序)时,遇到了一个让人头疼的文件上传问题。本项目是嵌入在安卓应用中的小程序,需要实现视频文件上传功能。由于是wgt项目,所以是在安卓应用内部运行的小程序,对兼容性和稳定性要求较高。
第一版方案:uni.chooseVideo插件
最初我使用了UniApp官方的 uni.chooseVideo
插件来实现视频选择功能。看起来很简单,但很快就遇到了兼容性问题:
兼容性问题
- 低版本安卓:基本可以正常使用
- 高版本安卓:打开相册时出现乱码,用户体验极差
这个问题让我意识到,官方插件在不同安卓版本上的兼容性并不稳定,特别是在wgt项目中,兼容性问题更加突出。
第二版方案:原生插件
为了解决兼容性问题,我们的团队想出了一个合理保守的方案:让安卓同事开发一个原生插件,通过 sendNativeEvent
来调用。
技术实现
// 使用sendNativeEvent调用原生插件
uni.sendNativeEvent('插件名称xxx', {title: "",multiple: false,filetypes: "video/mp4"
}, (ret) => {// 处理返回结果
});
优势
- 完全控制文件选择逻辑
- 解决了安卓版本兼容性问题
- 用户体验更加稳定
- 使用自己开发的插件后,确实解决了眼下的兼容性问题
新的挑战:文件大小限制
解决了兼容性问题后,我遇到了更大的挑战——文件上传大小限制。
问题现象
当文件超过20MB时,UniApp默认的nginx服务器直接返回错误:
<html>
<head><title>413 Request Entity Too Large</title>
</head>
<body>
<center><h1>413 Request Entity Too Large</h1>
</center>
<hr><center>nginx</center>
</body>
</html>
问题分析
通过多次验证,我发现:
- 20MB以下:可以正常"通过"
- 20MB以上:UniApp默认的nginx直接断开连接,请求无法发送出去
这里的"通过"很重要,说明20MB是一个关键的分界线。
深入调查:uni.chooseVideo的秘密
于是我好奇,为什么会出现这样的情况呢?然后我用 uni.chooseVideo
插件来试一下,发现了一个有趣的现象:
观察到的现象
- 选择视频后会显示长时间的loading,等待时间很长,至少30秒
- 最终上传的文件大小比原文件小很多
- 本地40MB的视频被压缩到14MB
关键发现
原来 uni.chooseVideo
插件默认会自动压缩视频!这就是为什么它能够处理大文件的原因。
uni.chooseVideo
有个属性叫 compressed
,你需要把它关掉,不然它就默认给你压缩了。但是问题来了,即使把 compressed
关掉也没用,如果文件超过20MB的话,还是会被断掉。
解决方案:手动视频压缩
那只能选择压缩视频的方法了。所以我使用 sendNativeEvent
选择完毕视频后,也给视频进行压缩。UniApp官网也提供了免费的压缩插件,我就直接使用了它,压缩效果还不错,但有一点慢。使用的是 uni.compressVideo
。
技术实现
// 判断文件类型
const isVideo = this.isVideoFile(file);if (isVideo) {// 视频文件进行压缩const compressedFile = await compressVideoWithUni(file);await this.handleFileUpload(compressedFile);
} else {// 非视频文件直接上传await this.handleFileUpload(file);
}// 使用UniApp官方压缩插件
export const compressVideoWithUni = async (file) => {return new Promise((resolve, reject) => {uni.compressVideo({src: file.path,quality: 'low', // 使用最低质量,最大压缩success: (res) => {const compressedFile = {...file,path: res.tempFilePath,size: res.size};resolve(compressedFile);},fail: (error) => {reject(new Error(error.errMsg || '压缩失败'));}});});
};
文件类型判断
isVideoFile(file) {if (!file || !file.path) return false;const extension = file.path.split('.').pop()?.toLowerCase();const videoExtensions = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm', 'm4v', '3gp'];return videoExtensions.includes(extension);
}
最终效果
解决的问题
- ✅ 安卓版本兼容性问题
- ✅ 文件大小限制问题
- ✅ 用户体验优化
技术特点
- 智能处理:只有视频文件才进行压缩
- 容错机制:压缩失败时自动降级到原文件
- 用户友好:显示压缩进度和状态
- 性能优化:避免不必要的压缩操作
经验总结
技术要点
- UniApp的局限性:官方插件在某些场景下存在兼容性问题
- 文件大小限制:20MB是
uni.uploadFile
默认nginx的限制 - 视频压缩的重要性:大文件必须压缩才能正常上传
开发建议
- 测试覆盖:在不同安卓版本上充分测试
- 用户体验:提供清晰的状态反馈
- 错误处理:实现完善的容错机制
- 性能考虑:避免不必要的文件处理
技术选型
- 原生插件 > 官方插件(在兼容性要求高的场景)
- 手动压缩 > 依赖默认行为(在需要精确控制的场景)
UniApp官方文档不够完善
在解决这个问题的过程中,我发现了一个让人无语的问题:UniApp官方文档的严重不足!
文档缺失问题
uni.uploadFile
文档:完全没有提到20MB的文件大小限制uni.chooseVideo
文档:虽然有compressed
属性说明,但没有明确说明压缩的具体行为和时间- 错误处理:413错误在官方文档中没有任何说明
开发者体验问题
- 需要自己摸索和踩坑才能发现问题
- 官方文档过于简单,缺乏实际使用场景的说明
- 错误信息不够友好,调试困难
建议改进
- 完善文档:明确标注各种限制和约束
- 错误说明:提供常见错误的解决方案
- 最佳实践:增加实际项目中的使用建议
结语
这个问题的解决过程让我深刻体会到,在移动端开发中,兼容性和性能优化永远是绕不开的话题。通过这次经历,我不仅解决了当前的问题,还为自己积累了宝贵的经验。
同时,我也深刻认识到官方文档的局限性,作为开发者,我们不能完全依赖官方文档,需要在实际项目中不断探索和总结。
记住:有时候官方插件并不是最佳选择,根据具体需求选择合适的技术方案才是王道!
本文记录了UniApp文件上传大小限制问题的完整解决过程,希望能为遇到类似问题的开发者提供参考。