表单在前端提交时,后端用 formidable.IncomingForm() 方法获取表单中的内容,这时候就会有一个问题:有点绕,我写的清楚点
前端第一次提交(数据库中没有任何信息)表单到后端时,这时候在后端有2种情况:
- 1.表单中没有图片等媒体信息(只有字符串的文字信息)
- 2.表单中存在图片+文字混合等信息
后端这时候要做什么?
首先,是用form方法获取到前端传到值,然后做判断
- 1.当取到的是纯文字的数据,那么直接获取fields,再做2个判断(数据库中是否有数据),这里我用的是用户名查找,如果查到了说明这是一次更新操作,没查到说明这是第一次设置,所以数据库中无数据,前者作update操作,后者直接插入insert就可以了。然后后端对这两种情况
- 2.图片+文字内容的数据,同理第一条,做2次判断,即数据库中是否已经有资料,判断这是更新还是直接插入
所以后端这里一共是4次判断,由于我用的是原生的mongodb,并没有用mongooose,所以代码是有点冗余,但是逻辑基本都是一样的。
坑来了:如果你第一次设置资料完成后,再次点开这个表单,为了用户体验,需要将你之前存入的信息,显示到你重新打开到表单上到,所以坑就是这个图片到问题,图片的确能显示到预览到div(divison)框中,但是上传到时候,后端拿不到
为什么?
因为并没有上传操作,用户看到了预览端地方有图片,当他不想更改时,他就不会有这个上传图片端操作去改变图片,他可能只是想改下昵称什么的,然后问题就是,后面你会拿不到图片的链接,因为你在前端没传,后端存到数据库的是个空值,页面中请求时自然也拿到的是空值,不显示。
解决方法:后端将每次存入图片的url地址,返回给前端,前端将这个url存入,然后当上传表单时,就会有这么个行为:
- 第二次更新头像时,我(用户)看到表单上显示了我之前上传的头像,我不想改,我修改了其他文字资料如昵称,我点击上传,这时表单中没有文件file(图片)被上传,只上传了文字资料,但是这个文字资料中包含了我从后端拿到到URL图片地址,所以问题被解决了,后端接着做上面的第二条判断(也就是当没有图片信息上传时,其实这时候已经拿到图片到URL了)
代码如下:
前端:
setPersonal() {
let { url,username,e_mail,nickname } = this.ruleForm//对象解析
let userInfo = {url,username,e_mail, nickname};
//userInfo就是要传到后端到文字内容,url为后端传过来到图片地址
this.ruleForm.param.append("message", JSON.stringify(userInfo));
this.$axios.post("/api/userInfoAdd", this.ruleForm.param).then(res => {
if (res.data == "0") {
swal({
title: "设置成功!",
icon: "success",
button: "Aww yiss!"
}).then(() => {
this.$router.go(0);
});
} else if (res.data == "1") {
swal({
title: "更新成功!",
icon: "success",
button: "Aww yiss!"
}).then(() => {
this.$router.go(0);
});
} else {
swal({
title: "设置失败!",
text: "网络好像有点问题",
icon: "error",
button: "yiss Aww!"
});
}
});
},
//获取个人资料显示在表单
getPersonal() {
let getPersonalData = this.$axios
.get("/api/userInfoData", {
params: {
username: this.ruleForm.username
}
})
.then(res => {
let { url,username,e_mail,nickname } = res.data;
this.ruleForm.nickname=nickname
//这里写的冗余了,因为我之前data下的对象的格式存的值也包含其他的内容,所以不能这接做对象替换,这个不急
this.ruleForm.sex=sex
this.ruleForm.hometown=hometown
this.ruleForm.job=job
this.ruleForm.birthday=birthday
this.ruleForm.desc=desc
this.ruleForm.url=uploadUrl
console.log(this.ruleForm.url,11111)
});
},
后端:
//添加用户信息
app.post("/userInfoAdd", function(req, res) {
//图片信息
let form = formidable.IncomingForm();
form.uploadDir = path.normalize(__dirname + "/public/tempDir");
form.parse(req, (err, fields, files) => {
//非图片信息,不需要存图片信息
let birthday = JSON.parse(fields.message).birthday.slice(0, 10);
let { url,e_mail, username, nickname} =JSON.parse(fields.message);
console.log(url,'liu')
let upLoadFile = files.file;//获取图片文件
//存在图片时
if (upLoadFile) {//如果这个图片存在
let extname = path.extname(upLoadFile.name); //后缀名
let filename = uuid() + extname; //文件名
let oldPath = upLoadFile.path;
let newPath = path.join(__dirname, "public/upload", filename);
var uploadUrl = `http://localhost:3001/uploads/${filename}`;
fs.rename(oldPath, newPath, err => {
if (!err) {
MongoClient.connect(DBurl, function(err, db) {
db.collection("userInfo").findOne({ username }, function(er, rs) {
if (!rs) {
db.collection("userInfo").insertOne(
{ url,e_mail, username, nickname},
function(er, rs) {
if (rs) {
res.send("0", file); //用户信息插入成功
}
}
);
} else {
db.collection("userInfo").findOneAndUpdate(
{ username },
{ url,e_mail, username, nickname},
function(er, rs) {
if (rs) {
res.send("1"); //用户信息更新成功
}
}
);
}
});
});
console.log("上传成功"); //上传成功
} else {
console.log("上传失败");
}
});
} else {
MongoClient.connect(DBurl, function(err, db) {
db.collection("userInfo").findOne({ username }, function(er, rs) {
if (!rs) {
db.collection("userInfo").insertOne(
{ src, username, nickname, desc, sex, hometown, job, birthday },
function(er, rs) {
if (rs) {
res.send("0"); //用户信息插入成功
}
}
);
} else {
var uploadUrl = url
db.collection("userInfo").findOneAndUpdate(
{ username },
, { url,e_mail, username, nickname},,
function(er, rs) {
if (rs) {
res.send("1"); //用户信息更新成功
}
}
);
}
});
});
}
});
});
//获取用户信息,也就是当前端网页点击表单时,能看到之前填的信息的api接口
app.get("/userInfoData", function(req, res) {
let { username } = req.query;
console.log(username,99999)
MongoClient.connect(DBurl, function(err, db) {
db.collection("userInfo").findOne({ username }, function(er, rs) {
if (rs) {
console.log(rs,00000)
res.send(rs);
}
});
});
});
总结:这个坑其实更前端没太大关系吧,应该是后端要处理的,但是前端也要知道这个逻辑才能更好的配合工作
一些话:去年用nodeJS做图片上传时候也遇到了这个问题,大概是国庆的时候,当时也是这个问题,然后被搁置了,今晚花了20多分钟解决了。遇事多思考,可能上面代码是冗余了,因为没mvc,我直接用app路由做的,也没有model层提取数据库的代码操作,所以看起来就是好多MongoClient.connect,本质上还是做几个判断,是更新还是第一次设置的问题
这看起来是个小问题吧,小到我们平时在设置更新QQ资料到时候,也没有考虑过,本身这个问题也不是用户需要考虑到到,用户只关注方便到使用,所以当我在做到这些到时候,我在思考,当我是程序员跟用户2个身份时,我想如何方便的使用,什么第一次设置,第二次更新这些判断都要提前设定好,这也是我们程序员的工作,用户体验很重要
BTW,彭于晏真的帅,自律真的能改变一个人
Comments | 5 条评论
balabala了一大堆,做了一个逻辑整理,
有点乱吧2333
Hi there everyone, it’s my first pay a quick visit
at this web site, and post is truly fruitful designed for me, keep up posting these types of posts.
@fleck 5600 water softener prices ^_^
Everything is very open with a clear description of the
issues. It was really informative. Your website is extremely helpful.
Thanks for sharing!
It’s an amazing paragraph in favor of all the online users; they
will take benefit from it I am sure.