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

MVC重构Node.js项目时出现Cannot read properties of undefined (reading 'admin')错误求助

问题排查与解决方案

错误根源

出现TypeError: Cannot read properties of undefined (reading 'admin')的核心原因是:

  • 控制器未将req/res参数传递给用例函数,导致用例中req为空对象,无法读取req.user
  • 路由存在重复定义,部分逻辑被覆盖
  • 用例层直接处理响应渲染,违背MVC职责划分

分步修复

1. 修正控制器的参数传递与职责

控制器需要接收请求上下文req/res,并将用户信息传递给用例,最后负责视图渲染:

// controller/todos/index.js
const TODOS = require("../../models/usecases/todo");
module.exports = {
  getAllTodos: async (req, res) => {
    try {
      console.log("in the controller");
      // 传递当前用户给用例,而非空对象
      const todos = await TODOS.getAllTodos(req.user);
      
      // 根据用户身份渲染对应页面
      if (req.user.admin) {
        res.render("admin-dashboard.ejs", {
          todoTasks: todos,
          user: req.user,
        });
      } else {
        res.render("todo.ejs", {
          todoTasks: todos,
          user: req.user,
        });
      }
    } catch (error) {
      console.error(error);
      res.status(500).send("获取待办事项失败");
    }
  },
  // 其他方法保持不变
};

2. 重构用例层的业务逻辑

用例层仅负责数据查询,返回业务数据,不处理HTTP响应:

// models/usecases/todo.js
const TodoTask = require("../../models/entity/ToDoTask");

const getAllTodos = async function (user) {
  if (user.admin === true) {
    // 使用await替代回调,符合async函数规范
    return await TodoTask.find({});
  } else {
    return await TodoTask.find({ "user.id": user._id });
  }
};

module.exports = { getAllTodos };

3. 修复路由重复定义问题

路由中/admin-dashboard被定义两次,后续路由会覆盖前面的。合并认证与权限校验逻辑:

// 路由文件
"use strict";
const express = require("express");
const router = express.Router();
const {
  ensureAuthenticated,
  forwardAuthenticated,
} = require("../controller/authentication/index");

const { isAdmin } = require("../controller/authentication/adminAuthMiddleware");

const {
  getAllTodos,
  createTodo,
  getTodo,
  editTodo,
  deleteTodo,
} = require("../controller/todos/index");

// Welcome Page
router.get("/", forwardAuthenticated, (req, res) => res.render("landing"));

// 用户仪表盘:需登录
router.get("/dashboard", ensureAuthenticated, getAllTodos);
// 管理员仪表盘:需登录+管理员权限
router.get("/admin-dashboard", ensureAuthenticated, isAdmin, getAllTodos);

router.post("/dashboard", createTodo);
router.route("/edit/:id").get(getTodo).post(editTodo);
router.route("/remove/:id").get(deleteTodo);

module.exports = router;

4. 验证认证中间件有效性

确保ensureAuthenticated中间件正确将用户信息挂载到req.user,示例实现:

// controller/authentication/index.js
module.exports.ensureAuthenticated = (req, res, next) => {
  if (req.isAuthenticated()) {
    return next();
  }
  req.flash('error_msg', '请先登录');
  res.redirect('/login');
};

若req.user仍为undefined,需检查Passport.js的序列化/反序列化配置是否正确。


内容的提问来源于stack exchange,提问作者Syed Shuja Shah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 04:45:42