前端上传图片

探讨了前端上传图片至服务器的两种方式:Base64编码与FormData文件流,分析了各自的优缺点,尤其强调了大图使用文件流的必要性。文章详细介绍了在WebApp环境下,如何利用HBuilder SDK实现手机拍照图片的上传,包括File对象获取、图片压缩、Base64转换及最终的FormData上传过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前端上传图片到服务器,一般会有两种方式:

1. Base64编码

2. FormData文件流

首先,如果图片转为 Base64 后,除了体积会增大33%左右外,更大的问题是,你以为你是在以字符串的格式传输二进制。 其实非也,尤其是你把它转为 JSON 传给后端,由于变成了需要解析的字符串,对后端的压力会陡增,你会明显看到处理速度的急剧下滑。以及,你还需要去调 nginx 配置文件以避免 nginx 觉得你字符串过长,直接报错 Entity Too Large 把包拒掉。

所以,Base64 更适合用来处理小图,比如头像或小图标之类,保存在本地,以减少 Http 的请求次数;而大图比较适合用 FormData 文件流来传输。


而我最近的需求是把手机拍照的图片上传到服务器,所以确定了用文件流来处理。

而我们的应用是经过 Hbuilder 打包后的 Web App, 加持了 iOS 和 Android 的原生 SDK 的功能,所以面临着两个选择:

  1. 使用 Web 原生的 <input> 来拍照及选取相册
  2. 使用 Hbuilder 的提供的 SDK

如果用原生 <input> ,可以这么写(项目用的是 Vue):

<input type="file" accept="image/*" capture="camera" @change="onChange" multiple>

实际上呢,坑还不少。。。

加上capture="camera"这个属性,是为了让手机可选相机,不过真实情况是:

  • 部分 Android 手机上调用不了相机,始终只能选相册;(解决办法:请教 Android 原生开发的童鞋吧)

  • 苹果手机上,只能拍照,不能选相册;(解决办法:判断 iOS,如果是 iOS 就去掉 capture 属性)

所以, Android 不能调用相机这点,就把 Web 原生的方案毙掉了,后来转用 HBuilder 的 SDK;


接下来的大致思路:

  1. 获取到 File 对象

  2. FileReader 转成 dataUrl

  3. canvas 接收 dataUrl

  4. 对图片进行宽高比的设置(压缩大小)

  5. canvas.toDataURL 将压缩后的图片生成新的 Base64 编码

  6. 执行回调函数,将新的 Base64 转换为文件

  7. 最后拿到文件,构造 FormData 对象上传至服务器。

特别要注意的是:

  • FormData 的请求方式,每个参数都需要通过 append 方法添加进去;

  • 不需要单独设置请求头的 Content-Type,系统自动会设定为 multipart/form-data


经过几天线上的验证,事实证明,只用文件流传图片,有时也会报 Entity too large 这个错误,后来经过定位发现在 canvas.toDataURL 时,最好用 jpeg 格式进行压缩,不要用 png 的无损压缩,这点非常关键!

---The End

转载于:https://juejin.im/post/5ba5be55e51d451a3f4c0a23

### 实现 uni-app 前端上传图片功能 在 `uni-app` 中实现前端上传图片的功能主要依赖于其内置的 API 和组件。通过使用 `chooseImage` 接口可以选择本地图片,再利用 `uploadFile` 将选中的图片文件上传服务器。 #### 使用 chooseImage 选择图片 此方法允许用户从相册或相机选取一张或多张图片[^2]: ```javascript async function selectImages() { try { const res = await uni.chooseImage({ count: 9, // 默认最多可选数量 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'] // 可以指定来源是相册还是相机,默认二者都有 }); console.log('Selected images:', res.tempFilePaths); return res.tempFilePaths; } catch (err) { console.error(err); } } ``` #### 利用 uploadFile 进行上传操作 一旦获取到了临时路径列表,则可以调用 `uploadFile` 来完成实际的数据传输过程[^1]: ```javascript function uploadImages(filePaths) { filePaths.forEach(filePath => { uni.uploadFile({ url: 'https://example.com/upload', // 替换成自己的服务器地址 filePath, name: 'file', formData: { user: 'test' }, // 如果有额外参数要传递给后台的话放这里 success(uploadRes) { console.log(`Upload succeeded! Server response is ${JSON.stringify(JSON.parse(uploadRes.data))}`); }, fail(error) { console.error(`Failed to upload file at path ${filePath}`, error); } }); }); } ``` 为了使整个流程更加流畅友好,在页面上通常会配合 `<view>` 或者其他容器来显示已选择但还未提交的照片缩略图,并提供删除按钮让用户能够取消某些项的选择;另外还可以加入进度条指示当前正在执行的任务状态等交互设计元素[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值