uniapp 上传二进制流图片
文章目录
- 场景
- 🟢一、步骤
- 1.1、选择图片
- 1.2、 读取图片为二进制数据
- 1.3、上传二进制数据到服务器
- 🟢二、项目案例
- 2.1、替换头像案例
- 2.1、uView u-upload 上传封面
- 🟢 三、关键注意事项
- 3.1 二进制流与 FormData 区别
- 3.2 性能优化
- 3.3 跨平台适配
- ✒️总结
场景
在日常开发中,常需实现用户头像更换、图片附件上传等功能。通过将图片转换为二进制流上传,可灵活适配不同后端接口需求,本文将详细介绍具体实现步骤及项目案例。
🟢一、步骤
在 UniApp 中上传二进制流图片,一般需要经过选择图片、读取为二进制数据、上传二进制数据到服务器这几个主要步骤
1.1、选择图片
使用 uni.chooseMedia 或 uni.chooseImage 方法让用户从相册或相机选择图片。
uni.chooseMedia(推荐,UniApp 3.1.0+ 支持)或 uni.chooseImage 调用系统媒体选择器。
uni.chooseMedia({count: 1, // 选择图片的数量mediaType: ['image'], // 只选择图片success: (res) => {const tempFilePath = res.tempFiles[0].tempFilePath;// 后续可将 tempFilePath 用于读取二进制数据},fail: (err) => {console.error('选择图片失败:', err);}
});
1.2、 读取图片为二进制数据
使用 uni.getFileSystemManager().readFile 方法将选择的图片文件读取为ArrayBuffer 格式二进制数据
uni.getFileSystemManager().readFile({filePath: tempFilePath,success: (fileRes) => {const binaryData = fileRes.data;// 后续可将 binaryData 用于上传},fail: (err) => {console.error('读取文件失败:', err);}
});
1.3、上传二进制数据到服务器
通过 uni.request 发送二进制流,需注意请求头设置为 application/octet-stream。
uni.request({url: 'https://xxx/upload', // 服务器上传接口地址method: 'POST',data: binaryData,headers: {'Content-Type': 'application/octet-stream'},success: (res) => {if (res.statusCode === 200) {console.log('上传成功:', res.data);} else {console.error('上传失败,状态码:', res.statusCode);}},fail: (err) => {console.error('上传失败:', err);}
});
🟢二、项目案例
2.1、替换头像案例
uni.chooseMedia+uni.getFileSystemManager().readFile方案实现
页面结构
<view class="img-box" @click="onAvatatChange"><image mode="aspectFill" class="img" :src="addformData.avatar"></image><view class="text">点击更换头像</view></view>
逻辑实现
// 修改头像onAvatatChange() {// 调用拍照/选择图片uni.chooseMedia({count: 1,mediaType: ['image'],success: (res) => {console.log(res.tempFiles[0].tempFilePath)const tempFilePath = res.tempFiles[0].tempFilePath;// 读取图片文件为二进制数据uni.getFileSystemManager().readFile({filePath: tempFilePath,success: (fileRes) => {const binaryData = fileRes.data;// 上传二进制数据到服务器this.uploadBinaryData(binaryData, tempFilePath);},fail: (err) => {console.error('读取文件失败:', err);uni.showToast({title: '读取文件失败',icon: 'none'});}});}})},uploadBinaryData(binaryData, tempFilePath) {uni.uploadFile({url: "https://xxxx/file/upload",method: 'POST',formData: binaryData,filePath: tempFilePath,name: "file",header: {'Authorization': uni.getStorageSync('token'),'Content-Type': 'multipart/form-data'},success: (res) => {let resut = JSON.parse(res.data)if (resut.code == 200) {this.addformData.avatar = resut.data.url}},})},
2.1、uView u-upload 上传封面
页面结构
<u-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple:maxCount="1"></u-upload>
// 删除图片deletePic(event) {console.log('删除', event)this.api.FileDelete({filePath: event.file.baseUrl}).then(res => {console.log('删除附件', res)uni.showToast({title: '删除成功',icon: 'success',duration: 1500});this[`fileList${event.name}`].splice(event.index, 1);})},// 新增图片async afterRead(event) {// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式let lists = [].concat(event.file);let fileListLen = this[`fileList${event.name}`].length;lists.map((item) => {this[`fileList${event.name}`].push({...item,status: "uploading",message: "上传中",});});for (let i = 0; i < lists.length; i++) {const result = await this.uploadFilePromise(lists[i]);let item = this[`fileList${event.name}`][fileListLen];this[`fileList${event.name}`].splice(fileListLen,1,Object.assign(item, {status: "success",message: "",url: result.url,name: result.name,baseUrl: result.baseUrl,}));fileListLen++;}},//上传图片uploadFilePromise(file) {console.log('file', file)return new Promise((resolve, reject) => {uni.getFileSystemManager().readFile({filePath: file.url,encoding: 'binary',success: (readRes) => {console.log('readRes', readRes)console.log('文件内容长度:', readRes.data.length);uni.uploadFile({// url: "http://xxx/file/upload", // 仅为示例,非真实的接口地址url: "https://xxxx/file/upload", // 仅为示例,非真实的接口地址filePath: file.url,name: "file",// header: {// 'Authorization': uni.getStorageSync('token'),// 'Content-Type': 'application/octet-stream'// },header: {// 添加请求头'Authorization': uni.getStorageSync('token'),// 可以添加其他请求头'Content-Type': 'multipart/form-data'},formData: readRes,// formData: {// user: "test",// },success: async (res) => {console.log('res文件上传', res)setTimeout(() => {resolve(JSON.parse(res.data).data);uni.showToast({title: '上传成功',icon: 'success',duration: 1500});}, 1000);},fail: (err) => {reject(err);}});},fail: (err) => {reject(err);}});});},
🟢 三、关键注意事项
3.1 二进制流与 FormData 区别
方式 | 适用场景 | 请求头设置 | 后端 |
---|---|---|---|
二进制流 | 纯文件字节流传输 | Content-Type: application/octet-stream | 直接读取请求体字节数据 |
FormData 封装 | 需附带其他字段(如业务参数) | Content-Type: multipart/form-data | 通过 file 字段解析文件 |
3.2 性能优化
- 压缩图片:上传前通过
uni.compressImage
压缩图片,减少传输数据量。 - 并行上传:使用
Promise.all
并行处理多图上传(需注意服务器接口是否支持)。 - 进度监听:通过
uni.uploadFile
的onProgressUpdate
回调显示上传进度条。
3.3 跨平台适配
- 小程序平台:
uni.chooseMedia
自动适配微信/支付宝/字节等小程序的图片选择接口。 - H5 平台:需确保服务器支持跨域请求(设置
Access-Control-Allow-Origin
)。 - App 平台:需在 manifest 中配置文件读写权限(
FS_WRITE_ACCESS
)。
✒️总结
UniApp 中上传二进制流图片的核心在于:
- 通过
uni.chooseMedia
或uni.chooseImage
获取图片临时路径; - 使用文件系统 API 读取为二进制数据;
- 根据后端要求选择
uni.request
(二进制流)或uni.uploadFile
(FormData 表单)上传。
实际开发中,建议优先使用 uni.chooseMedia
统一跨平台体验,并根据接口规范灵活设置请求头。对于复杂场景(如多图上传、进度显示),可结合组件库(如 uView)或自定义指令优化交互体验。
如果本文对你有帮助,欢迎点赞支持!如需进一步探讨前端或 UniApp 开发,可访问我的个人主页「前端初见」,期待与你共同成长!
如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对前端端或者对python感兴趣的朋友,请多多关注💖💖💖,咱们一起探讨和努力!!!
👨🔧 个人主页 : 前端初见