表单在前端提交时,后端用 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,彭于晏真的帅,自律真的能改变一个人


爬。