el-upload+formData自定义方法传图片踩坑!
利用formData上传文件遇到的错误及解决方案
真的吐了!!!!!!!!!!!!!!!!!!!!
一个bug改了要一个周!!!!!!
问题描述
啥都感觉没问题,却出现了问题。前端el-upload+formData传文件,后端用multipartFile解析文件,但是收到的图片数组为null!!!!!!!!!
踩坑记录
el-upload图片回显
- 直接将处理on-change事件函数中的file加入到fileList数组,但是这样不利于处理数据
handleChange(file, fileList) {
this.form.file.push(file);
}
2.构造file-list中元素,将其push进file-list数组
handleChange(file, fileList) {
//查阅element-plus文档,发现file-list数组中元素需要满足的对象格式为{name:'xxx',url:'xxxx'}
let reader = new FileReader();
reader.readAsDataURL(file.raw);
reader.onload = (e) => {
this.form.file.push({ name: file.raw.name, url: e.target.result });
}
this.file.push(file.raw);
fileList = this.form.file;
}
文件传输格式
- 前端发送请求时,请求头需要设置成如下
且不要再次序列化!!!!!!!!!!!!!!
header:{
'Content-Type': 'multipart/form-data;boundary=<calculated when request is sent>'
}
- 后端处理请求时,需要用multipartFile解析图像文件
默认提交
-
默认submit,数据以formData的形式发送给后端
formData中的键值对{key:value}中的key是表单元素中的name值,value是表单属性中的value值(vue中可以为v-model绑定的值) -
表单外的附带data如何随着表单一起默认提交(如不用在表单中填写的user)
解决方案:附带数据可以放在一个隐藏的input中,submit时跟着一起提交
<el-input name="user" v-model="user" v-show="false"/>
-
el-upload组件的name默认为file,前后端接口需对应
-
默认submit执行后会刷新并跳转页面,没有办法调试
解决方案:用iframe接收跳转的页面,使得原页面只刷新不跳转
<el-form
ref="form"
:model="form"
label-width="80px"
enctype="multipart/form-data"
method='post'
action='接口的url'
target='myFrame'
>
</el-form>
<!-- 接受跳转的iframe -->
<iframe name='myFrame' style='display:none;'></iframe>
- 默认submit无回调函数
解决方案:自定义submit方法,如下文
自定义提交
- formData传输格式后端无法用multipartFile解析
-
发现的契机:
1.起初我是直接把handleChange(file, fileList) 中的file加入文件数组this.form.file中,查看发出去的请求时,发现formData中的文件数组的类型是[object Object]
于是我打印this.form.file数组发现这是一个proxy数组,真正的文件在proxy.raw中,也就是说真正的文件是file.raw;
2.接着我就试着将handleChange(file, fileList) 中file.raw的File数组append进formData发送给后端,此时请求中文件数组的类型变成了[object File]。我真的以为没问题了,但是后端仍然解析不了[苦涩.jpg]
3.自定义提交不行了,只能再试试表单默认submit。当我试了很多次终于用iframe接收跳转的页面,解决了原页面总跳转无法调试的问题时,我看到了默认submit发出的请求中文件数组的格式是(binary)。
4.我终于搞懂了原因,我应该把文件以(binary)的形式传给后端解析。 -
疑惑:为什么formData.append(‘file’,文件数组)之后不是binary形式呢?
(此间我们做了无数尝试,用fileReader读文件转成Blob,binaryString…都失败了) -
解决:直接向formData中添加文件数组,文件不能被分转成(binary),只有每次添加一个文件时该文件才会被转成(binary)传输给后端。
故多次向formData中同一个键名下添加文件即可
https://blog.csdn.net/weixin_43249665/article/details/100084637
Final解决方案
html
<el-form ref="form" :model="form" label-width="80px" enctype="multipart/form-data" >
</el-form-item>
<el-input name="user" v-model="user" v-show="false"/>
</el-form-item>
<el-form-item label="上传图片">
<el-upload
list-type="picture-card"
action="#"
:limit="9"
:on-change="handleChange"
:on-remove="handleRemove"
:on-exceed="handleExceed"
:auto-upload="false"
:multiple="false"
:file-list="form.file"
accept="image/png,image/gif,image/jpg,image/jpeg"
>
<i class="el-icon-plus"></i>
</el-upload>
</el-form-item>
<div style="width: fit-content; margin: 0 auto 20px">
<el-button type="primary" @click="handleSubmit()">提交</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</div>
</el-form>
data
form:{
user;
file:[];//保存fileList
}
file[];//
javascript
handleChange(file, fileList) {
//查阅element-plus文档,发现file-list数组中元素需要满足的对象格式为{name:'xxx',url:'xxxx'}
let reader = new FileReader();
reader.readAsDataURL(file.raw);
reader.onload = (e) => {
this.form.file.push({ name: file.raw.name, url: e.target.result });
}
this.file.push(file.raw);
fileList = this.form.file;
},
onCancel() {//取消
if (confirm("该操作将放弃所有表单内容。确定取消填写吗?")) close();
},
handleRemove(file) {
// 1.从filelist数组中,找到图片对应的索引值
const i = this.form.files.findIndex(x => x.name === file.name)
// 2.调用splice方法,移除图片信息
this.form.files.splice(i, 1);
const j = this.files.findIndex(x => x.name === file.name)
this.files.splice(j, 1);
},
handleExceed() {
this.$message(
{
message: '图片数不能超过9张',
type: 'warning'
}
)
},
handleSubmit() {
let formData = new FormData();
for (let i = 0; i < this.file.length; i++) {
formData.append('file', this.file[i]);
}
formData.append('user', this.user);
this.axios({
url: '······',
method: 'post',
data: {
formData
},
headers: {
'Content-Type': 'multipart/form-data;boundary=<calculated when request is sent>'
}
}).then(
(res) => {}
},
function (err) {
console.log(err)
}
ps:在此特别感谢后端调试的朋友们还有帮我改前端代码的学长。