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

EJS页面无限加载求助:路由文件错误定位

页面无限加载问题排查

我正在学习Web开发,跟着教程开发时页面出现无限加载的情况,怀疑问题出在路由文件里,但找不到具体错误,求帮忙指出。我已经核对过教程内容,检查了所有依赖,还是没解决问题,欢迎任何建议和批评,谢谢!

Model

const mongoose = require("mongoose");

const photoBasePath = "uploads/photoImages";

const photoSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
  },
  description: {
    type: String,
  },
  createdAt: {
    type: Date,
    required: true,
    default: Date.now,
  },
  imageName: {
    type: String,
    required: true,
  },
  tags: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Tag",
    },
  ],
});

module.exports = mongoose.model("Photo", photoSchema);
module.exports.photoBasePath = photoBasePath;

Route

const { render } = require("ejs");
const express = require("express");
const router = express.Router();
const multer = require("multer");
const path = require("path");
const Photo = require("../models/photo");
const Tag = require("../models/tag");
const uploadPath = path.join("public", Photo.photoBasePath);
const imageMimeTypes = ["image/jpeg", "image/png", "image/gif"];
const upload = multer({
  dest: uploadPath,
  fileFilter: (req, file, callback) => {
    callback(null, imageMimeTypes.includes(file.mimetype));
  },
});

//All Photos Route
router.get("/", async (req, res) => {
  res.send("All Photos");
});

//New Photo Route
router.get("/new", async (req, res) => {
  //res.send("New Photo");
  renderNewPage(res, new Photo());
});

//Create Photo Route
router.post("/", upload.single("photo"), async (req, res) => {
  const fileName = req.file != null ? req.file.filename : null;

  const photo = new Photo({
    name: req.body.name,
    description: req.body.description,
    imageName: fileName,
    tags: req.body.tags,
  });

  try {
    const newPhoto = await photo.save();
    res.redirect("photos");
  } catch {
    renderNewPage(res, photo, true);
  }
});

async function renderNewPage(res, photo, hasError = false) {
  try {
    const tags = await Tag.find({});
    const params = {
      tags: tags,
      photo: photo,
    };
    const photo = new Photo();
    if (hasError) params.errorMessage = "Error Creating Photo.";
    res.render("photos/new", params);
  } catch {
    renderNewPage(res, photo, true);
  }
}

module.exports = router;

View

new.ejs

<h2>New Photo</h2>
<form action="/photos" method="POST" enctype="multipart/form-data">
  <%- include('_form_fields') %>

  <a href="/photos">Cancel</a>
  <button type="submit">Create</button>
</form>

_form_fields.ejs

<div>
  <label>Name</label>
  <input type="text" name="name" value="<%= photo.name %>" />
</div>
<div>
  <label>Tags</label>
  <select name="tag">
    <% tags.forEach(tag => { %> <% if (tag.id === photo.tag) { %>
    <option selected label="<%= tag.name %>" value="<%= tag.id %>"></option>
    <%} else {%>
    <option label="<%= tag.name %>" value="<%= tag.id %>"></option>
    <% } %> <% }) %>
  </select>
</div>
<div>
  <label>Photo</label>
  <input type="file" name="photo" />
</div>

<div>
  <label>Description</label>
  <textarea type="description"> <%= photo.description %> </textarea>
</div>

问题分析与修复

1. 路由函数无限递归触发死循环

renderNewPage的catch块中直接递归调用自身,没有任何终止条件。一旦Tag.find({})抛出错误(比如数据库连接失败),就会进入无限递归,导致服务器持续处理请求,页面无限加载。

修复:
替换递归调用,改为返回错误提示或重定向:

catch (err) {
  console.error(err);
  res.status(500).send("加载失败,请稍后重试");
  // 或者重定向到列表页:res.redirect("/photos");
}

2. 函数内部重复声明变量覆盖参数

renderNewPage里重新声明const photo = new Photo();,直接覆盖了传入的photo参数,导致视图无法获取之前的表单数据,同时可能引发逻辑混乱。

修复:
删除这行重复声明的代码。

3. 视图与模型字段不匹配

  • 模型中tags是数组类型,但视图里select的name是tag(单数),提交后req.body.tag是单个ID,无法正确赋值给数组字段。
  • 视图中判断tag.id === photo.tag,但模型里不存在photo.tag属性,应该判断当前标签是否在photo.tags数组中。

修复(多选场景):
修改视图的select标签:

<select name="tags" multiple>
  <% tags.forEach(tag => { %>
    <option <%= photo.tags.includes(tag.id) ? 'selected' : '' %> label="<%= tag.name %>" value="<%= tag.id %>"></option>
  <% }) %>
</select>

修复(单选场景):
如果只需要单选标签,修改模型的字段定义:

// 替换原有的tags数组字段
tag: {
  type: mongoose.Schema.Types.ObjectId,
  ref: "Tag",
}

同时保持视图中select的name为tag,判断逻辑不变。

4. 图片字段必填性问题

模型中imageName设置了required: true,但如果用户未上传图片,fileName会是null,保存时会抛出错误,触发之前的递归问题。

修复:
要么允许imageName为空(去掉required: true),要么在上传逻辑中强制要求用户上传图片,或者设置默认图片路径。

内容的提问来源于stack exchange,提问作者Antoni Kaleta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 12:40:35