lihuayuli 2025-05-27 17:26 采纳率: 100%
浏览 14
已结题

为什么我运行后端代码,点update后报404?

运行结果:

img


点击“修改”:

img

点击“删除”:

img

代码:
controllers层:

const router = require("../routes/guestBookRoutes");
const guestbookDAO = require("../models/guestbookModel");
const dbDAO = new guestbookDAO("guestbook.db");
//调用model层的constructor方法(构造函数)
// 创建了一个实例对象dbDAO,用于操作嵌入式数据库。
// const dbDAO = new guestbookDAO();
// 创建了一个实例对象dbDAO,用于操作嵌入式数据库。
exports.landing_page = function (req, res) {
  res.send("Hello! Welcome to my application!");
  // dbDAO.init();
  //初始化数据库,即在内存中创建一个空的数组。
};
exports.entries_list = function (req, res) {
  // res.send("<h1>Guestbook</h1>");
  dbDAO
    .getAllEntries()
    .then((list) => {
      //then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
      res.render("entries", {
        //渲染名为entries的视图
        title: "Guestbook",
        //要渲染的内容,key:value形式,
        //这里的key是mustache文件的title,value是每个循环中的内容,
        // 也就是想显示的内容。
        entries: list,
        //这里的entries要和mustache文件中的{{#entries}}对应起来。
        //这里的list是数据库中的所有记录,要和mustache文件中的{{entries}}对应起来。
      });
    })
    .catch((err) => {
      console.log("err:", err);
    }); //catch在then后面,捕获then中的错误。
};
exports.peter_entries = function (req, res) {
  res.send("<h1>Processing Peter's Entries, see terminal</h1>");
  dbDAO
    .getPetersEntries()
    .then((list1) => {
      //then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
      res.render("entries_p", {
        //渲染名为entries的视图
        title: "Peter's Guest Book",
        //要渲染的内容,key:value形式,
        //这里的key是mustache文件的title,value是每个循环中的内容,
        // 也就是想显示的内容。
        entries_p: list1,
        //这里的entries要和mustache文件中的{{#entries}}对应起来。
        //这里的list是数据库中的所有记录,要和mustache文件中的{{entries}}对应起来。
      });
    })
    .catch((err) => {
      console.log("err:", err);
    });
};
exports.show_new_entry = function (req, res) {
  res.render("newEntry", {
    title: "New Entry",
  });
};
exports.post_new_entry = function (req, res) {
  if (!req.body.author || !req.body.subject || !req.body.contents) {
    res.status(400).send("Author不能为空!");
    return;
  }
  dbDAO.addEntry(req.body.author, req.body.subject, req.body.contents);
  //跟name属性对应
  res.redirect("/guestbook");
};
exports.show_user_entries = function (req, res) {
  let user = req.params.author; // URL:后的内容,是个形参
  dbDAO
    .getUserEntries(user)
    .then((list) => {
      //then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
      res.render("entries", {
        //渲染名为entries的视图
        title: user + " Guestbook",
        //要渲染的内容,key:value形式,
        //这里的key是mustache文件的title,value是每个循环中的内容,
        // 也就是想显示的内容。
        entries: list,
        //这里的entries要和mustache文件中的{{#entries}}对应起来。
        //这里的list是数据库中的所有记录,要和mustache文件中的{{entries}}对应起来。
      });
    })
    .catch((err) => {
      console.log("err:", err);
    }); //catch在then后面,捕获then中的错误。
};
exports.update_entry = function (req, res) {
  const _id = req.params.id;
  dbDAO
    .updateEntry(_id)
    .then((list) => {
      //then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
      res.render("update", {
        //渲染名为entries的视图
        title: user + " Update Guestbook",
        //要渲染的内容,key:value形式,
        //这里的key是mustache文件的title,value是每个循环中的内容,
        // 也就是想显示的内容。
        entries: list,
        //这里的entries要和mustache文件中的{{#entries}}对应起来。
        //这里的list是数据库中的所有记录,要和mustache文件中的{{entries}}对应起来。
      });
    })
    .catch((err) => {
      console.log("err:", err);
    }); //catch在then后面,捕获then中的错误。
  // res.redirect("/guestbook");
};
exports.show_update_entry = function (req, res) {
  const _id = req.params.id; // 从URL获取参数
  // 查询数据库获取要更新的条目(需确保`getEntryById`方法存在)
  dbDAO
    .updateEntry(_id) 
    .then((entry) => {
      if (!entry) {
        return res.status(404).send("Entry not found");
      }
      res.render("update", {
        title: "Update Entry",
        id: _id, // 将ID传递给视图
        entry: entry, // 将条目数据传递给视图
      });
    })
    .catch((err) => {
      console.error("Error fetching entry for update:", err);
      res.status(500).send("Internal Server Error");
    });
};
exports.delete_entry = function (req, res) {
  const _id = req.params.id;
  dbDAO
    .deleteEntry(_id)
    .then((list) => {
      //then拿到promise对象,list是resolve的值,也就是数据库中的所有记录。
      res.redirect("/guestbook");
    })
    .catch((err) => {
      console.log("err:", err);
    }); //catch在then后面,捕获then中的错误。
};
// exports.new_entry = function (req, res) {
//   res.send("<h1>Not yet implemented:show a new entry page.</h1>");
//   dbDAO.init();
// };
// exports.show_user_entries;
exports.about_page = function (req, res) {
  // 返回位于public文件夹下的about.html文件
  res.redirect("about.html");
  //直接重定向,app.use(express.static(public));的作用
  dbDAO.init();
};
exports.image = function (req, res) {
  // 返回位于public/img/logo.jpg的图片文件
  res.redirect("logo.jpg");
  dbDAO.init();
};
exports.status_404 = function (req, res) {
  res.status(404); // 设置HTTP状态码为404
  res.send("Oops! Page not found."); // 返回错误提示
};
exports.status_500 = function (err, req, res, next) {
  console.log("error:", err);
  res.status(500);
  res.type("text/plain");
  res.send("Internal Server Error");
};

view层:

update.mustache:<!DOCTYPE html>
<html lang="en">
  <head>
    {{>header}}
  </head>
  <body class="container">
  <h1>{{title}}</h1>
    <form action="/update/{{id}}" method="post" role="form">
      <div class="form-group">
        <label for="author">Author</label>
        <input
          type="text"
          class="form-control"
          id="author"
          name="author"//每一个框一定要有一个name属性
          value="{{entry.author}}"
          required
        />
      </div>
      <div class="form-group">
        <label for="subject">Subject</label>
        <input
          type="text"
          class="form-control"
          id="subject"
          name="subject"
          value="{{subject}}"
          required
        />
        
      </div>
      <div class="form-group">
        <label for="contents">Entry text</label>
        <textarea
          class="form-control"
          id="contents"
          name="contents"
          value="{{contents}}"
          rows="3"
          required
        >
        {{entry.contents}}
        </textarea>
      </div>
      <div class="form-group">
        <input type="submit" value="Post entry" class="btn btn-primary" />
      </div>
    </form>
  </body>
</html>
entries.mustache:<html lang="en">
<head>
    {{>header}}
</head>

<body class="container">
//read-only不可编辑
//点修改按钮,id作为参数,找到对应记录,跳转到对应mustache
//作者只能修改自己的,对应登录的名字
//删除要弹出警告框,避免误操作
    <h1>{{title}}</h1>
    <div class="text-right">
        <a href="/new" class="btn btn-primary">
            Write in the guest book
        </a>
    </div>
    {{#entries}}
    
    <div class="card">
        <div class="card-header">
            {{subject}}
        </div>
        <div class="card-body">
            <div class="card-text">
                {{contents}}
            </div>
            <div class="card-text">
                Written by <a href="/posts/{{author}}">{{author}}</a>,on {{published}}
                <a href="/update/{{id}}" >修改</a>
                <!-- 修改删除链接为表单 -->
<form action="/delete/{{id}}" method="post">
  <button type="submit" class="delete-btn">删除</button>
</form>
            </div>
        </div>
    </div>
    {{/entries}}
    {{^entries}}
            No entries yet!
        {{/entries}}
</body>

</html>
{! <div class="card-text">
{! Written by <a href="/posts/?author={{author}}">{{author}}</a>, on 
{! {{published}}
{! </div>


model层:

const nedb = require("@seald-io/nedb"); //nedb是一个变量
class GuestBook {
  constructor(dbFilePath) {
    if (dbFilePath) {
      this.db = new nedb({ filename: dbFilePath, autoload: true });
      //db是该对象的一个属性,用来存储该数据库的引用信息。
      console.log("DB created:" + dbFilePath);
    } else {
      this.db = new nedb();
    }
  }

  init() {
    this.db.insert(
      {
        subject: "I liked the exhibition",
        contents: "nice",
        published: "2020-02-16",
        author: "Peter",
      },
      function (err, newDoc) {
        if (err) {
          console.log("Error:" + err);
        } else {
          console.log("Peter inserted!");
        }
      }
    );
    this.db.insert(
      {
        subject: "Didn't like it",
        contents: "A really terrible style!",
        published: "2020-02-18",
        author: "Ann",
      },
      function (err, newDoc) {
        if (err) {
          console.log("Error:" + err);
        } else {
          console.log("Ann inserted!");
        }
      }
    );
  }
  addEntry(author_value, subject_value, contents_value) {
    this.db.insert(
      {
        subject: subject_value,
        contents: contents_value,
        published: new Date().toISOString().split("T")[0],
        author: author_value,
      },
      function (err, newDoc) {
        if (err) {
          console.log("Error:" + err);
        } else {
          console.log("日期为:" + new Date().toISOString());
          console.log("addEntry inserted!");
        }
      }
    );
  }

  getAllEntries() {
    //return a Promise object, which can be resolved or rejected
    return new Promise((resolve, reject) => {
      //Promise对象可以记录异步操作是成功还是失败
      //resolve记录成功时的状态,reject记录失败时的报错信息,
      // 同时变化了Promise的状态。
      //避免回调地狱,用Promise代替回调函数。
      this.db.find({}, function (err, entries) {
        if (err) {
          reject(err);
          console.log("getAllEntries Promise rejected:" + err);
        } else {
          resolve(entries);
          console.log("getAllEntries Promise resolved: ", entries);
        }
      });
    });
  }
  getPetersEntries() {
    return new Promise((resolve, reject) => {
      this.db.find({ author: "Peter" }, function (err, entries_p) {
        if (err) {
          reject(err);
          console.log("getPetersEntries Promise rejected:" + err);
        } else {
          resolve(entries_p);
          console.log("getPetersEntries Promise resolved:", entries_p);
        }
      });
    });
  }
  getUserEntries(userName) {
    return new Promise((resolve, reject) => {
      this.db.find({ author: userName }, function (err, entries_u) {
        if (err) {
          reject(err);
          console.log("getUserEntries Promise rejected:" + err);
        } else {
          resolve(entries_u);
          console.log("getUserEntries Promise resolved:", entries_u);
        }
      });
    });
  }

  updateEntry(userID, author, contents) {
    return new Promise((resolve, reject) => {
      this.db.update(
        { _id: userID },
        {
          $set: {
            author: req.body.author, // 从表单获取数据
            contents: req.body.contents,
            published: new Date().toISOString().split("T")[0],
            // 注意这里的写法,$set是用来更新数据的,而不是直接赋值。
            // 这样可以避免覆盖掉其他字段的数据。
          },
        },
        function (err, updatedDoc) {
          if (err) {
            reject(err);
            console.log("updateEntry Promise rejected:" + err);
          } else {
            resolve(updatedDoc);
            console.log("updateEntry Promise resolved:", updatedDoc);
          }
        }
      );
    });
  }
  deleteEntry(userID) {
    return new Promise((resolve, reject) => {
      this.db.delete({ _id: userID }, function (err, db_deleted) {
        if (err) {
          reject(err);
          console.log("deleteEntry Promise rejected:" + err);
        } else {
          resolve(db_deleted);
          console.log("deleteEntry Promise resolved:", +userID + " deleted");
        }
      });
    });
  }
}

module.exports = GuestBook;

router层:

const express = require("express");
const { entries_list } = require("../controllers/guestbookControllers");
const router = express.Router();
const controllers = require("../controllers/guestbookControllers");
router.get("/", controllers.landing_page);
router.get("/guestbook", controllers.entries_list);
router.get("/peter", controllers.peter_entries);
router.get("/new", controllers.show_new_entry);
router.get("/posts/:author", controllers.show_user_entries);
router.get("/update/:id", controllers.show_update_entry);
router.post("/update/:id", controllers.update_entry);
router.post("/delete/:id", controllers.delete_entry);
//加上:变成一个变量,可以匹配任何东西
// router.get("/posts", controller.get("/posts", function (request, response) {
//     console.log("filtering for author ", request.query.author);
//   }));
router.post("/new", controllers.post_new_entry);
router.get("/about", controllers.about_page);
router.get("/img/logo.jpg", controllers.image);
router.use(controllers.status_404);
router.use(controllers.status_500);
module.exports = router; //导出路由,非常重要


  • 写回答

6条回答 默认 最新

  • 檀越@新空间 2025-05-27 17:27
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    从你的描述和代码来看,点击“修改”按钮时出现404错误的原因可能是路由配置不完整或路径未正确匹配。以下是问题分析和解决方案:


    问题分析

    1. 路由未定义

      • 在代码中,update_entryshow_update_entry 方法已经定义,但需要确保它们对应的路由路径在 guestBookRoutes.js 中被正确注册。
    2. 前端请求路径问题

      • 如果前端发送的请求路径与后端路由不匹配,服务器会返回404错误。例如,前端可能发送了 /update/:id 而后端只监听了 /update
    3. 视图文件未找到

      • 如果 update 模板文件不存在,或者路径拼写错误,也可能导致404错误。

    解决方案

    1. 检查并完善路由配置

    确保在 guestBookRoutes.js 文件中定义了 update_entryshow_update_entry 的路由。

    // routes/guestBookRoutes.js
    const express = require('express');
    const router = express.Router();
    
    // 引入控制器
    const guestbookController = require('../controllers/guestbookController');
    
    // 定义路由
    router.get('/update/:id', guestbookController.show_update_entry); // 显示修改页面
    router.post('/update/:id', guestbookController.update_entry);       // 提交修改
    
    module.exports = router;
    
    • 关键点
      • 使用 GET /update/:id 来显示修改页面。
      • 使用 POST /update/:id 来提交修改。

    2. 修改 update_entry 控制器

    update_entry 方法中,需要接收前端传递的表单数据,并调用数据库更新逻辑。以下是修正后的代码:

    exports.update_entry = function (req, res) {
      const _id = req.params.id;
      const { author, subject, contents } = req.body;
    
      // 验证表单字段是否为空
      if (!author || !subject || !contents) {
        res.status(400).send("Author, Subject, and Contents are required!");
        return;
      }
    
      // 调用数据库更新方法
      dbDAO.updateEntry(_id, author, subject, contents)
        .then(() => {
          res.redirect("/guestbook"); // 更新成功后重定向到主页
        })
        .catch((err) => {
          console.error("Error updating entry:", err);
          res.status(500).send("Internal Server Error");
        });
    };
    
    • 关键点
      • 使用 req.body 接收前端传递的数据。
      • 验证表单字段是否为空。
      • 调用数据库的 updateEntry 方法完成更新。

    3. 前端表单提交

    确保前端表单的 action 属性指向正确的路径,并使用 POST 方法提交数据。例如:

    <!-- update.mustache -->
    <form action="/update/{{id}}" method="post">
      <input type="text" name="author" placeholder="Author" value="{{entry.author}}">
      <input type="text" name="subject" placeholder="Subject" value="{{entry.subject}}">
      <textarea name="contents" placeholder="Contents">{{entry.contents}}</textarea>
      <button type="submit">Update</button>
    </form>
    
    • 关键点
      • action 属性指向 /update/:id
      • 使用 method="post" 提交表单数据。

    4. 检查视图文件

    确保 update.mustache 文件存在,并且路径正确。如果路径错误,也会导致404错误。


    5. 调试日志

    在开发环境中启用调试日志,查看具体的请求路径和响应情况。例如,在 update_entry 方法中添加日志:

    exports.update_entry = function (req, res) {
      console.log("Received update request for ID:", req.params.id);
      console.log("Form data:", req.body);
      ...
    };
    

    总结

    通过以上步骤,可以解决点击“修改”按钮时出现404的问题。以下是完整的解决方案清单:

    1. 完善路由配置:确保 guestBookRoutes.js 中定义了 GET /update/:idPOST /update/:id
    2. 修正控制器逻辑:验证表单数据并调用数据库更新方法。
    3. 前端表单提交:确保表单的 actionmethod 正确。
    4. 检查视图文件:确保模板文件存在且路径正确。
    5. 调试日志:查看请求路径和响应情况。

    如果仍有问题,请提供更多细节,例如前端代码、路由配置或具体的错误信息。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?

问题事件

  • 系统已结题 6月5日
  • 已采纳回答 5月28日
  • 修改了问题 5月27日
  • 创建了问题 5月27日