You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 18:36:51