前言
Uniapp
真是个大坑?不管你是否赞同这个观点,反正我是这么认为的。 但是,又没有开发原生的成本和精力,所以就跟鸡肋一样。 食之无味,弃之可惜。
今天我就分享一下我遇到的一个坑。

开始
项目需求,移动端上传图片,一下就想到使用uniapp
自带的上传组件
这里用到的是vue3写法
vue
<uni-file-picker ref="images"> </uni-file-picker>
如果是多张图片的上传,遍历images
内的filesList
数组
javaScript
const sceneFileImgs = [];
if (images.value.filesList && images.value.filesList.length > 0) {
images.value.filesList.forEach((i, index) => {
sceneFileImgs.push({ name: `sceneFileImgs[${index}].png`, uri: i.url });
});
}
按照Uniapp
的文档,字段名称格式为

这里files
的对象名称要根据接口来定。
他们要的字段是什么名字,你就跟他命名一致,像我这里是sceneFileImgs
formData
是接口需要提交的额外参数,这里不用 再包含 sceneFileImgs

javaScript
uni.uploadFile({
url:'https://juejin.cn/api/submit',
files: sceneFileImgs,
header: {
Authorization: uni.getStorageSync('token'),
},
formData: formDatas,
complete: res => {
if (data.code === 0) {
toast('提交成功');
} else {
toast(`${data.msg}`);
}
},
});
H5上开始调试,完美!
Android上调试,完美!
但是!

IOS就会失败,接口都没有进行请求
黑人问号
网上搜了一圈,说是IOS在接口上要强制手动添加 'Content-Type': 'multipart/form-data'
但是

加上去之后发现,后端报错了
这啥问题呢?
报错提示后端在解析你的请求头时,发现在你的请求头里没有找到
boundary
boundary
就是formData
数据的分隔符,
所以,正是因为你写了content-type
之后,覆盖了浏览器自己帮你拼上的boundary
那怎么办?
那好,咱获取一下formData
的 boundary
,再拼到请求头上。
想法太天真了
因为boundary
获取不到,前端无论你在哪里都获取不到
所以陷入了死循环
那到底怎么解决呢?

只能放弃uniapp
提供的upload
方法

自己定义接口,使用axios
或者ajax
,这样IOS在请求的时候会自动 给你加上Content-Type
接下来就是见证奇迹的时候
附录
附上自定义的接口代码
JavaScript
const sceneFileImgs = [];
if (images.value.filesList && images.value.filesList.length > 0) {
images.value.filesList.forEach((i, index) => {
sceneFileImgs.push({ name: i.name, uri: i.url });
});
}
Object.keys(formDatasClone).forEach(key => {
formData.append(key, formDatasClone[key]);
});
// 请求头的配置,不需要再配置 Content-Type
// 无论是IOS还是安卓都会自动帮你添加上去
const config = {
headers: {
Authorization: uni.getStorageSync('token'),
},
};
for (let index = 0; index < sceneFileImgs.length; index++) {
const el = sceneFileImgs[index];
// 将blodUrl 转换成 File格式
await getFileFromUrl(el.uri, el.name)
.then(response => {
formData.append(`sceneFileImgs[${index}]`, response);
})
}
axios.post('https://juejin.cn/api/submit', formData, config).then(res => {
if (res.data.code === 0) {
toast('提交成功');
} else {
toast(`${res.data.msg}`);
}
})
getFileFromUrl
函数
JavaScript
// 将blodUrl 转换成 File格式
const getFileFromUrl = (url, fileName) => {
return new Promise((resolve, reject) => {
var blob = null;
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.setRequestHeader('Accept', 'image/png');
xhr.responseType = 'blob';
// 加载时处理
xhr.onload = async () => {
// 获取返回结果
blob = xhr.response;
let file = new File([blob], fileName, { type: 'image/png' });
resolve(file);
};
xhr.onerror = e => {
reject(e);
};
// 发送
xhr.send();
});
};
后续
移动端上传的图片太大,我们可以进行压缩处理 在getFileFromUrl
函数返回file结果进行压缩