NodeJS+EJS+MongoDB博客编辑提交后修改内容无法保存
问题描述
基于NodeJS、EJS模板引擎、MongoDB搭建的博客站点,数据库中已存储的文章可正常在前端展示,但对已有文章执行编辑修改并提交后,变更内容无法成功保存入库。
现有实现代码
后端接口代码(app.js)
app.post('/do-edit-post/:postId',(req, res) => { const requestedPostId = req.params.postId; Post.updateOne({ _id:requestedPostId }, {$set: { title: req.body.title, author:req.body.author, content:req.body.content } }, function (err, result) { if (err) { console.log(err); } else { console.log("Post Updated successfully"); res.redirect("/admin"); } }); });
前端编辑页模板代码(editpostID.ejs)
<form class="" action="/do-edit-post" method="post"> <div class="form-group"> <label>Title</label> <input class="form-control" hidden="<%= post._id %>"> <input class="form-control" text="text" name="postTitle" value="<%= title %>"> <label>Author</label> <input class="form-control" text="text" name="postAuthor" value="<%= author %>"> <label>Post</label> <!-- Text area matching the selector specified in the TinyMCE configuration --> <textarea id="mytextarea" class="form-control" name="postBody" rows="5" cols="30" value=<%- content %>> </textarea> </div> <button class="btn btn-warning" type="submit" name="button">Save</button> </form>
导致保存失败的核心问题
- 前后端路由规则不匹配:后端定义的更新接口路径为
/do-edit-post/:postId,要求URL路径中必须携带动态参数postId指定待更新文章,但前端表单的action属性仅填写了/do-edit-post,没有拼接文章ID,请求要么匹配不到接口返回404,要么后端拿到的postId为空,无法定位到要修改的文章。 - 表单字段名和后端取值字段完全不对应:后端更新逻辑中从
req.body取的字段是title、author、content,但前端三个输入控件的name属性分别是postTitle、postAuthor、postBody,后端根本拿不到用户提交的修改内容,拿到的三个字段全是undefined。 - 文章ID传递写法完全错误:之前尝试加的隐藏域写法不符合规范,
hidden是元素的布尔显示属性,不是用来存值的;要通过表单传值的输入控件必须设置name属性,存ID的隐藏域正确写法应为<input type="hidden" name="xxx" value="文章ID">,原有写法不会把ID随表单提交到后端。 - 表单控件属性写法错误:标题、作者输入框错误将
type属性写为text,写成了text="text",不符合HTML规范;textarea标签没有value属性,原有内容必须写在<textarea>和</textarea>标签之间才能正确加载到编辑器,原有写法打开编辑页时无法正确回显文章内容。 - 后端缺少异常校验逻辑:没有校验传入的文章ID格式是否合法,也没有判断更新操作是否匹配到了对应文章,出现异常时仅打印错误、没有给前端返回明确提示,很容易出现静默失败的情况。
修正方案
修正后的EJS表单代码
<!-- 表单action直接拼接文章ID,和后端路由规则对应 --> <form class="" action="/do-edit-post/<%= post._id %>" method="post"> <div class="form-group"> <label>Title</label> <!-- 修正type属性,name属性和后端字段一一对应 --> <input class="form-control" type="text" name="title" value="<%= title %>"> <label>Author</label> <input class="form-control" type="text" name="author" value="<%= author %>"> <label>Post</label> <!-- textarea默认内容放在标签对中间,name对应后端content字段 --> <textarea id="mytextarea" class="form-control" name="content" rows="5" cols="30"><%- content %></textarea> </div> <button class="btn btn-warning" type="submit" name="button">Save</button> </form>
如果不想把ID拼在URL路径里,也可以在表单内加正确的隐藏域传ID:
<input type="hidden" name="postId" value="<%= post._id %>">,同时把后端路由改成/do-edit-post,从req.body.postId取待更新文章ID即可,两种方式保持前后端匹配就行。
优化后的后端接口代码
// 引入MongoDB ObjectId用于校验ID格式,Mongoose环境下可省略该校验 const { ObjectId } = require('mongodb'); app.post('/do-edit-post/:postId',(req, res) => { const requestedPostId = req.params.postId; // 校验ID格式合法性 if (!ObjectId.isValid(requestedPostId)) { return res.status(400).send('无效的文章ID'); } Post.updateOne( { _id: requestedPostId }, {$set: { title: req.body.title.trim(), author: req.body.author.trim(), content: req.body.content }}, function (err, result) { if (err) { console.log(err); return res.status(500).send('文章更新失败'); } // 判断是否匹配到待更新文章 if (result.matchedCount === 0) { return res.status(404).send('待编辑的文章不存在'); } console.log("Post Updated successfully"); res.redirect("/admin"); } ); });
注意:如果项目中没有配置
express.urlencoded中间件,需要在app.js路由定义前加上app.use(express.urlencoded({ extended: true })),否则req.body会是undefined,无法拿到表单提交内容。
内容的提问来源于stack exchange,提问作者Masoman
相关产品推荐
相关产品推荐

