在 UniApp 中,uni.uploadFile API 通常需要一个本地文件路径 (filePath),而不能直接上传 Base64 字符串。因此,核心思路分为两步:
- 转存:将 Base64 字符串写入本地临时文件,获取文件路径。
- 上传 :使用
uni.uploadFile上传该本地文件。
由于 App/小程序 和 H5 的底层机制不同,处理方式有所区别。以下是完整的解决方案。
方案概览
场景一:App 端 (Android/iOS) 与 小程序
App 和小程序支持文件系统管理器 (FileSystemManager),这是最推荐、最稳定的方式。
1. 定义转换工具函数
我们需要一个函数,将 Base64 去掉头部(如果有),写入本地临时目录,并返回路径。
javascript
/**
* 将 Base64 字符串转为本地临时路径 (App/小程序专用)
* @param {String} base64data - 带头部的base64字符串 (如 data:image/png;base64,...)
* @returns {Promise<String>} - 返回本地临时文件路径
*/
function base64ToPath(base64data) {
return new Promise((resolve, reject) => {
// 1. 获取全局唯一的文件管理器
const fs = uni.getFileSystemManager();
// 2. 处理 Base64 头部,提取纯数据
// 正则匹配 data:image/png;base64, 这种格式
const base64Body = base64data.replace(/^data:image\/\w+;base64,/, "");
// 3. 创建临时文件路径 (使用时间戳确保文件名唯一)
// wx.env.USER_DATA_PATH 在小程序和App中均可用
const filePath = `${uni.env.USER_DATA_PATH}/temp_image_${Date.now()}.png`;
// 4. 写入文件
fs.writeFile({
filePath: filePath,
data: base64Body,
encoding: 'base64',
success: () => {
resolve(filePath);
},
fail: (err) => {
reject(err);
}
});
});
}
2. 调用并上传
javascript
async function handleUpload(base64Str) {
try {
uni.showLoading({ title: '处理中...' });
// 第一步:转为本地路径
const tempFilePath = await base64ToPath(base64Str);
console.log('本地临时路径:', tempFilePath);
// 第二步:上传文件
uni.uploadFile({
url: 'https://your-api.com/upload', // 你的后端接口
filePath: tempFilePath,
name: 'file', // 后端接收的字段名
formData: {
'user_id': '123' // 其他需要携带的参数
},
success: (uploadFileRes) => {
console.log('上传成功', uploadFileRes.data);
},
fail: (err) => {
console.error('上传失败', err);
},
complete: () => {
uni.hideLoading();
}
});
} catch (error) {
uni.hideLoading();
console.error('转换失败', error);
uni.showToast({ title: '图片处理失败', icon: 'none' });
}
}
场景二:H5 (Web端)
H5 无法像 App 那样直接访问本地文件系统,而是使用 Blob 对象。虽然 uni.uploadFile 在 H5 端也支持 file 对象,但更常见的做法是直接处理 Blob。
1. 定义转换工具函数 (Base64 转 Blob)
javascript
/**
* 将 Base64 转为 Blob 对象 (H5专用)
*/
function base64ToBlob(base64data) {
const arr = base64data.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
2. H5 端上传逻辑
在 H5 中,uni.uploadFile 内部会自动处理 Blob,或者你可以直接使用 uni.request 发送 FormData。
javascript
function handleH5Upload(base64Str) {
// 1. 转为 Blob
const blob = base64ToBlob(base64Str);
// 注意:uni.uploadFile 在 H5 端可以直接传 Blob 给 filePath 吗?
// 官方文档建议 H5 端将 blob 放入 file 对象中,或使用 FormData
// 下面是兼容性较好的 FormData 方式,使用 uni.request
const formData = new FormData();
formData.append('file', blob, 'image.png'); // 第三个参数是文件名
formData.append('user_id', '123');
uni.request({
url: 'https://your-api.com/upload',
method: 'POST',
data: formData,
// H5 端 fetch/xhr 会自动设置 Content-Type 为 multipart/form-data,不要手动设置 header
success: (res) => {
console.log('H5上传成功', res);
}
});
}
综合兼容写法 (推荐)
为了让代码一套逻辑跑通所有端,可以使用条件编译或运行时检查。
javascript
async function uploadBase64Image(base64Str) {
// #ifdef H5
// H5 逻辑
const blob = base64ToBlob(base64Str);
// 这里演示直接用 uni.uploadFile (UniApp H5端做了兼容,filePath 可以传 Blob 的 URL)
// 但更推荐上面 FormData 的方式。如果必须用 uni.uploadFile:
// const fileUrl = URL.createObjectURL(blob);
// 然后传 fileUrl 给 filePath,用完记得 URL.revokeObjectURL
// #endif
// #ifndef H5
// App 和 小程序 逻辑
try {
const filePath = await base64ToPath(base64Str);
uni.uploadFile({
url: 'https://api.example.com/upload',
filePath: filePath,
name: 'file',
success: (res) => {
console.log('上传完成', res);
}
});
} catch (e) {
console.error(e);
}
// #endif
}