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

NodeJS Express+MongoDB应用500错误:post-detail页面加载失败求助

问题:NodeJS Express + MongoDB 应用AJAX加载评论时500错误

开发基于NodeJS Express和MongoDB的Web应用时,在文章详情页(post-detail)通过AJAX加载评论出现Failed to load resource: the server responded with a status of 500 (Internal Server Error)错误。移除评论显示逻辑后页面及评论提交表单可正常显示,添加错误日志后得到如下报错:

ReferenceError:
C:\Users\DELL\Desktop\node-com4muz-filedata-database\views\home\post-detail.ejs:30
28|
29|


30| <% if (!comments) { %>
31|


32| This post might have comments. You can load them if you want to view
33| them.

comments is not defined
at eval ("C:\Users\DELL\Desktop\node-com4muz-filedata-database\views\home\post-detail.ejs":40:8)
at post-detail (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\ejs\lib\ejs.js:703:17)
at tryHandleCache (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\ejs\lib\ejs.js:274:36)
at View.exports.renderFile [as engine] (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\ejs\lib\ejs.js:491:10)
at View.render (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\express\lib\view.js:135:8)
at tryRender (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\express\lib\application.js:657:10)
at Function.render (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\express\lib\application.js:609:3)
at ServerResponse.render (C:\Users\DELL\Desktop\node-com4muz-filedata-database\node_modules\express\lib\response.js:1039:7)
at C:\Users\DELL\Desktop\node-com4muz-filedata-database\routes\home\posts.js:49:7
at processTicksAndRejections (node:internal/process/task_queues:96:5) { path:
'C:\Users\DELL\Desktop\node-com4muz-filedata-database\views\home\post-detail.ejs'
}


相关代码

app.js

const path = require('path');
 
const express = require('express');
 
const db = require('./data/database');
 
const adminRoutes = require('./routes/admin/blog');
 
const defaultRoutes = require('./routes/home/default');
const postsRoutes = require('./routes/home/posts');
const quotationsRoutes = require('./routes/home/quotations');
const contactsRoutes = require('./routes/home/contacts');
 
const app = express();
 
app.set('views', [
  path.join(__dirname, 'views/home'),
  path.join(__dirname, 'views/admin')
]);
app.set('view engine', 'ejs');
 
app.use(express.static('public'));
app.use('/public/admin/images', express.static('public/admin/images'));
 
app.use(express.urlencoded({ extended: true }));
 
app.use('/', adminRoutes);
 
app.use('/', defaultRoutes);
app.use('/', postsRoutes);
app.use('/', quotationsRoutes);
app.use('/', contactsRoutes);
 
app.use(function (req, res) {
  res.status(404).render('404');
});
 
app.use(function (error, req, res, next) {
  res.status(500).render('500');
});
 
db.connectToDatabase().then(function () {
  app.listen(3000);
});

routes/home/posts.js

const express = require('express');
const mongodb = require('mongodb');
 
// const uuid = require('uuid');
 
const db = require('../../data/database');
 
const ObjectId = mongodb.ObjectId;
 
const router = express.Router();
 
router.get('/blog', async function (req, res) {
  const posts = await db
    .getDb()
    .collection('posts')
    .find({})
    .project({ title: 1, summary: 1, 'author.name': 1, imagePath: 1 })
    .toArray();
  res.render('posts', { posts: posts });
});
 
router.get('/blog/:id', async function (req, res, next) {
  let postId = req.params.id;
 
  try {
    postId = new ObjectId(postId);
  } catch (error) {
    return res.status(404).render('404');
    // return next(error);
  }
 
  const post = await db
    .getDb()
    .collection('posts')
    .findOne({ _id: postId }, { summary: 0 });
 
  if (!post) {
    return res.status(404).render('404');
  }
 
  post.humanReadableDate = post.date.toLocaleDateString('en-US', {
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  });
  post.date = post.date.toISOString();
 
  res.render('post-detail', { post: post });
});
 
router.get('/blog/:id/comments', async function (req, res) {
  const postId = new ObjectId(req.params.id);
  const comments = await db
    .getDb()
    .collection('comments')
    .find({ postId: postId })
    .toArray();
 
  res.json(comments);
});
 
router.post('/blog/:id/comments', async function (req, res) {
  const postId = new ObjectId(req.params.id);
  const newComment = {
    postId: postId,
    title: req.body.title,
    text: req.body.text
  };
  await db.getDb().collection('comments').insertOne(newComment);
  res.redirect('/blog/' + req.params.id);
});
 
module.exports = router;

views/home/post-detail.ejs

<!DOCTYPE html>
<html lang="en">
  <head>
    <%- include('../admin/includes/head', { title: 'Post title' }) %>
    <link rel="stylesheet" href="/admin/styles/posts.css" />
    <link rel="stylesheet" href="/admin/styles/forms.css" />
    <script src="/home/scripts/comments.js" defer></script>
  </head>
  <body>
    <%- include('../admin/includes/header') %>
    <main id="post-detail">
      <article class="post-item">
        <img src="/<%= post.imagePath %>" alt="<%= post.title %>" />
        <h1><%= post.title %></h1>
        <section id="post-meta">
          <address>
            <a href="mailto:<%= post.author.email %>"
              ><%= post.author.name %></a
            >
          </address>
          |
          <time datetime="<%= post.date %>"><%= post.humanReadableDate %></time>
        </section>
        <hr />
        <section>
          <p id="body"><%= post.body %></p>
        </section>
      </article>
      <section id="comments">
        <% if (!comments) { %>
        <p>
          This post might have comments. You can load them if you want to view
          them.
        </p>
        <button
          id="load-comments-btn"
          class="btn btn-alt"
          data-postid="<%= post._id %>"
        >
          Load Comments
        </button>
        <% } else if (comments.length === 0) { %>
        <p>No comments found.</p>
        <% } else { %>
        <ol>
          <% for (const comment of comments) { %>
          <li><%- include('includes/comment-item', { comment: comment }) %></li>
          <% } %>
        </ol>
        <% } %>
      </section>
      <section id="comments-form">
        <h2>Leave a comment</h2>
        <form action="/posts/<%= post._id %>/comments" method="POST">
          <div class="form-control">
            <label for="title">Comment title</label>
            <input type="text" id="title" name="title" required />
          </div>
          <div class="form-control">
            <label for="text">Your comment</label>
            <textarea name="text" id="text" rows="3" required></textarea>
          </div>
          <button class="btn">Save Comment</button>
        </form>
      </section>
    </main>
  </body>
</html>

views/home/includes/comments/comment-item.ejs

<article class="comment-item">
  <h2><%= comment.title %></h2>
  <p><%= comment.text %></p>
</article>

public/home/scripts/comments.js

const loadCommentsBtnElement = document.getElementById('load-comments-btn');
 
async function fetchCommentsForPost() {
  const postId = loadCommentsBtnElement.dataset.postid;
  const response = await fetch(`/blog/${postId}/comments`);
  const responseData = await response.json();
  console.log(responseData);
}

 
loadCommentsBtnElement.addEventListener('click', fetchCommentsForPost);

解决方案

核心问题

EJS模板渲染post-detail.ejs时,尝试访问未定义的comments变量,直接抛出引用错误导致500状态码。根源是routes/home/posts.js的/blog/:id路由渲染模板时,仅传递了post对象,未初始化comments变量。

修复步骤

  1. 初始化模板变量
    修改routes/home/posts.js中/blog/:id路由的渲染代码,添加comments变量初始化:

    res.render('post-detail', { 
      post: post,
      comments: undefined // 或null,确保变量存在
    });
    

    模板中的if (!comments)判断即可正常执行,不会因变量未定义报错。

  2. AJAX加载后动态渲染评论
    当前comments.js仅打印评论数据,未更新页面。修改fetchCommentsForPost函数,获取数据后动态生成DOM:

    async function fetchCommentsForPost() {
      const postId = loadCommentsBtnElement.dataset.postid;
      const response = await fetch(`/blog/${postId}/comments`);
      const comments = await response.json();
      
      const commentsSection = document.getElementById('comments');
      commentsSection.innerHTML = '';
      
      if (comments.length === 0) {
        commentsSection.innerHTML = '<p>No comments found.</p>';
        return;
      }
      
      const ol = document.createElement('ol');
      comments.forEach(comment => {
        const li = document.createElement('li');
        li.innerHTML = `
          <article class="comment-item">
            <h2>${comment.title}</h2>
            <p>${comment.text}</p>
          </article>
        `;
        ol.appendChild(li);
      });
      commentsSection.appendChild(ol);
    }
    
  3. 修复评论提交表单路径
    post-detail.ejs中表单action属性写为/posts/<%= post._id %>/comments,但路由定义为/blog/:id/comments,需修改为:

    <form action="/blog/<%= post._id %>/comments" method="POST">
    

    避免提交评论时触发404错误。


内容的提问来源于stack exchange,提问作者Sofiane R

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 16:25:23