Express+MongoDB项目展示用户资料时遇TypeError问题求助
解决Express.js中TypeError: Cannot read properties of undefined (reading 'passport')问题
问题场景
开发基于Express.js+MongoDB的用户资料展示项目时,访问仪表盘页面触发以下错误:
TypeError: C:\Users\go\Downloads\mongo-class\views\dashboard.ejs:117 115| <div class="profile"> 116| >> 117| <div><img src=<%= foundUser.passport %> alt=<%= foundUser.fullname %>></div> 118| <div class="fullname"><p><%=foundUser.fullname %></p></div> 119| <div class="phone"><p><%= foundUser.phone %></p></div> 120| <div class="name"><p><%=foundUser.email %></p></div> Cannot read properties of undefined (reading 'passport') at eval ("C:\\Users\\go\\Downloads\\mongo-class\\views\\dashboard.ejs":13:36) at dashboard (C:\Users\go\Downloads\mongo-class\node_modules\ejs\lib\ejs.js:703:17) at tryHandleCache (C:\Users\go\Downloads\mongo-class\node_modules\ejs\lib\ejs.js:274:36) at View.exports.renderFile [as engine] (C:\Users\go\Downloads\mongo-class\node_modules\ejs\lib\ejs.js:491:10) at View.render (C:\Users\go\Downloads\mongo-class\node_modules\express\lib\view.js:135:8) at tryRender (C:\Users\go\Downloads\mongo-class\node_modules\express\lib\application.js:657:10) at Function.render (C:\Users\go\Downloads\mongo-class\node_modules\express\lib\application.js:609:3) at ServerResponse.render (C:\Users\go\Downloads\mongo-class\node_modules\express\lib\response.js:1039:7) at C:\Users\go\Downloads\mongo-class\app.js:139:9 at Layer.handle [as handle_request] (C:\Users\go\Downloads\mongo-class\node_modules\express\lib\router\layer.js:95:5)
错误根源分析
- 全局变量
foundUser不可靠:用全局变量存储登录用户信息,未登录直接访问/路由时foundUser为undefined,EJS直接访问其属性触发报错;且全局变量在多用户场景下会导致数据混乱。 - MongoDB连接未等待完成:
connectDB函数中mongoose.connect未加await,数据库未建立连接就执行查询,可能导致User.findOne返回undefined。 - 缺失依赖与边界处理:
login路由使用bcrypt但未导入,Admin模型未引入;同时未处理用户/管理员都不存在的情况。 - EJS模板无防御性判断:直接假设
foundUser一定存在,未做判空处理。
解决方案
1. 改用Session存储用户信息
全局变量不适合会话管理,用express-session存储用户登录状态:
- 安装依赖:
npm install express-session - 配置Session:
const session = require('express-session'); app.use(session({ secret: 'your-strong-secret-key', // 替换为实际密钥 resave: false, saveUninitialized: false, cookie: { secure: false } // 生产环境建议设为true(需HTTPS) }));
- 登录成功后存入Session:
if (isMatch) { req.session.user = foundUser; res.redirect('/'); }
2. 修复数据库连接逻辑
将connectDB改为异步函数,等待连接完成:
async function connectDB() { try{ console.log("connection to db") await mongoose.connect('mongodb://127.0.0.1:27017/db'); // 添加await console.log("connected") } catch (error) { console.log(error) } } connectDB()
3. 完善/路由逻辑
从Session获取用户信息,未登录则重定向到登录页:
app.get('/', (req, res )=>{ if (!req.session.user) { return res.redirect('/login'); } res.render('dashboard.ejs', {foundUser: req.session.user}) })
4. 补充缺失依赖与边界处理
在服务端顶部导入依赖:
const bcrypt = require('bcrypt'); const Admin = require('./model/admin'); // 替换为实际Admin模型路径
处理用户/管理员都不存在的情况:
}else{ const foundAdmin = await Admin.findOne({username:username}) if(foundAdmin){ // 原有管理员验证逻辑 } else { req.flash('info', 'Username or Password incorrect') res.redirect('/login') } }
5. EJS模板添加防御性判空
先判断foundUser是否存在,再访问属性:
<div class="profile"> <% if (foundUser) { %> <div><img src="<%= foundUser.passport %>" alt="<%= foundUser.fullname %>"></div> <div class="fullname"><p><%= foundUser.fullname %></p></div> <div class="phone"><p><%= foundUser.phone %></p></div> <!-- 注意:Schema中无email字段,此处改为username --> <div class="name"><p><%= foundUser.username %></p></div> <% } else { %> <p>请先登录</p> <a href="/login">前往登录</a> <% } %> </div>
修正后的完整服务端代码示例
const express = require('express') const app = express() const mongoose = require('mongoose'); const bcrypt = require('bcrypt'); const session = require('express-session'); const User = require('./model/reguser'); const Admin = require('./model/admin'); // 替换为实际路径 // 配置Session app.use(session({ secret: 'your-strong-secret-key', resave: false, saveUninitialized: false, cookie: { secure: false } })); // 解析表单数据 app.use(express.urlencoded({ extended: true })); async function connectDB() { try{ console.log("connection to db") await mongoose.connect('mongodb://127.0.0.1:27017/db'); console.log("connected") } catch (error) { console.log(error) } } connectDB() app.post('/login', async (req, res)=>{ const {username, password} = req.body const foundUser = await User.findOne({username:username}) if(foundUser){ const isMatch = await bcrypt.compare(password, foundUser.password) if (isMatch){ req.session.user = foundUser; res.redirect('/') }else{ req.flash('info', 'Username or Password incorrect') res.redirect('/login') } }else{ const foundAdmin = await Admin.findOne({username:username}) if(foundAdmin){ const isMatch = await bcrypt.compare(password, foundAdmin.password) if(isMatch){ req.session.user = foundAdmin; res.redirect('/admin') }else{ req.flash('info', 'Username or Password incorrect') res.redirect('/login') } } else { req.flash('info', 'Username or Password incorrect') res.redirect('/login') } } }) app.get('/', (req, res )=>{ if (!req.session.user) { return res.redirect('/login'); } res.render('dashboard.ejs', {foundUser: req.session.user}) }) // 启动服务 app.listen(3000, () => { console.log('Server running on port 3000'); });
内容的提问来源于stack exchange,提问作者Francis
相关产品推荐
相关产品推荐

