1、先说问题吧
我最近写了一个小程序,有一个拍照上传图片的功能,用Uview的u-upload组件写的,在小程序端测试一切功能正常,但是到H5端就发现图片没法传给后端或者传过去的图片后端无法识别,报500错误
原始代码
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].url)
let item = this[`fileList${event.name}`][fileListLen]
this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, {
status: 'success',
message: '',
url: result
}))
fileListLen++
}
},
uploadFilePromise(url) {
return new Promise((resolve, reject) => {
let a = uni.uploadFile({
url: this.baseUrl + '/common/upload',
filePath: url,
name: 'file',
formData: {},
header: {
Authorization: 'Bearer ' + getToken(),
'Content-Type': 'multipart/form-data'
},
success: (res) => {
this.lastList.push(JSON.parse(res.data).fileName)
this.files=this.lastList.join(',')
setTimeout(() => {
resolve(res.data.data)
}, 1000)
}
});
})
},
后台调试发现的问题
这里看似数据上传成功了,但是
发现后端并没有给返回数据,还来了个500,正常来说此时应该请教后端大佬的,但是这个地方比较特殊,问题在于前端传过去的数据有问题,但是这个不怪我们,而是uniapp官方背大锅,h5端与其他小程序、app在这个地方的处理方式不同,上面的方法其他端通用,唯独h5不行,请看vcr
uni.uploadFile(OBJECT) | uni-app官网
问题就在这里,h5端上传前必须转为file对象上传,其他端直接filePath就ok;
2、解决办法(超级大招)
代码放下边了,具体的改动就是我上面图片画红框的地方
整体流程思路:
1、基本上传的图片无非就是base64编码或者blob对象或者"blob:https://localhost:9090/2a68b651-7a69-48c8-9998-a9bdde15f52a"
2、无论是上面哪种情况,直接将base64转file或者blob转file
大多数应该是blob这种情况,下面也有示例代码,大家对照着抄就完事了
// 新增图片
async afterRead(event) {
// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file)
console.log(lists)
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++) {
// 将blob转为file对象的方法
function blobToFile(blob,fileName){
return new File([blob],fileName,{type:'image/png'})
}
// 获取blob对象
fetch(lists[i].url)
.then(response=>response.blob())
.then(blob=>{
// 将blob转换为file
let fileN = blobToFile(blob,lists[i].name)
// 上传file对象
this.uploadFilePromise(fileN)
.then(result=>{
let item = this[`fileList${event.name}`][fileListLen]
this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, {
status: 'success',
message: '',
url: result
}))
fileListLen++
})
})
}
},
uploadFilePromise(url) {
// console.log(fileN)
return new Promise((resolve, reject) => {
let a = uni.uploadFile({
url: this.baseUrl + '/common/upload',
file: url,
name: 'file',
formData: {},
fileType:"image",
header: {
Authorization: 'Bearer ' + getToken(),
// 'Content-Type': 'multipart/form-data'
},
success: (res) => {
console.log(res)
this.lastList.push(JSON.parse(res.data).fileName)
this.files=this.lastList.join(',')
console.log(this.files)
setTimeout(() => {
resolve(res.data.data)
}, 500)
}
});
})
},
有个地方忘说了,就是文件后缀名丢失的问题
接两张图给大家看一下,打印的内容分别是最开始没改代码时分别在小程序端、h5端运行打印lists[i]的结果
小程序:
h5端
对比就发现后缀少了,而官方给的解决办法就是我上面说的,上传file对象,不能直接给个filePath了。