登录状态下将MongoDB用户记录传递至所有EJS模板问题排查
Got it, let's figure out why your user record isn't making it to all EJS templates. The #1 issue here is almost certainly not handling asynchronous code correctly in your Express middleware—Mongoose queries like Legend.findById() are async, so if you don't wait for them to finish, your template will render before the user data is fetched.
Here's the Fix (Step-by-Step)
First, let's rewrite your middleware to properly handle the async database call. We'll use async/await for readability (callback syntax is included too if you prefer that).
1. Async/Await Middleware (Recommended)
This is the cleanest way to handle async operations in Express middleware:
// Make sure this middleware runs AFTER your session middleware (like express-session) app.use(async (req, res, next) => { // Check if user is logged in via session if (req.session.userId) { try { // Wait for the database query to complete const loggedInUser = await Legend.findById(req.session.userId); // Attach the user record to res.locals — all EJS templates can access this res.locals.currentUser = loggedInUser; } catch (err) { console.error("Failed to fetch user from DB:", err); // Pass errors to Express error handler (don't forget to call next!) return next(err); } } else { // If no user is logged in, set currentUser to null for clarity res.locals.currentUser = null; } // Critical: Call next() ONLY after the async operation finishes next(); });
2. Callback Syntax Alternative
If you're not using async/await, you need to wrap the query in a callback and call next() inside it:
app.use((req, res, next) => { if (req.session.userId) { Legend.findById(req.session.userId, (err, user) => { if (err) { console.error("DB Error:", err); return next(err); } res.locals.currentUser = user; next(); // Call next() AFTER fetching the user }); } else { res.locals.currentUser = null; next(); } });
Key Things to Double-Check
- Session Order: Ensure your session middleware (e.g.,
express-session) runs BEFORE this user middleware. Ifreq.sessionisundefined, youruserIdcheck will fail. - Model Validation: Confirm your
Legendmodel is correctly defined with Mongoose—make surefindById()is a valid method (it should be if you created the model withmongoose.model()). - Session Setup: Verify that when users log in, you're actually setting
req.session.userIdto the correct MongoDB document ID.
Using the Data in EJS Templates
Now you can access currentUser directly in any EJS template:
<% if (currentUser) { %> <nav> <span>Welcome, <%= currentUser.username %>!</span> <a href="/logout">Logout</a> </nav> <% } else { %> <nav> <a href="/login">Login</a> <a href="/signup">Sign Up</a> </nav> <% } %>
The core mistake was likely not waiting for the async findById() call to finish before moving on to render the template—Express doesn't automatically pause for async operations unless you explicitly tell it to with await or callbacks.
内容的提问来源于stack exchange,提问作者Asaf Aviv

