如何让HBS等待服务端req.user数据返回完成后再渲染页面
问题原因
你的判断完全准确,核心bug出在isLoggedIn中间件的异步流程控制错误:
- 嵌套查询订单的
db.query是异步回调操作,代码在订单查询刚发起、还没拿到结果给req.user.orders赋值时,就提前执行return next()放行到了路由渲染逻辑 - 最终渲染时能不能拿到orders字段完全取决于两次数据库查询的返回速度,才会出现随机成功、随机提示无订单的现象
- 原代码还存在
email变量未声明、缺少数据库查询错误分支、路由未处理未登录场景的隐患,会触发额外异常
修复步骤
1. 修正中间件异步执行顺序
必须等用户基础信息、关联订单全部查询完成,req.user完整赋值后再调用next()放行,修正后的回调版中间件代码:
exports.isLoggedIn = async (req, res, next) => { if (!req.cookies.jwt) { return next(); } try { const decoded = await promisify(jwt.verify)( req.cookies.jwt, process.env.JWT_SECRET ); // 查询用户基础信息 db.query( "SELECT * FROM user WHERE id = ?", [decoded.id], (error, userResult) => { if (error || !userResult.length) { return next(); } const currentUser = userResult[0]; // 查询关联订单,等结果返回后再赋值、放行 db.query( "SELECT * FROM orders WHERE email = ?", [currentUser.email], (orderError, orderResult) => { if (orderError) { return next(); } // 无订单时给空数组,避免模板读undefined报错 currentUser.orders = orderResult || []; req.user = currentUser; // 所有数据准备完成才执行下一步 return next(); } ); } ); } catch (error) { return next(); } };
如果用的是mysql2库,建议直接开启Promise API,用async/await写逻辑可以彻底避免回调嵌套导致的流程错误,示例写法:
// 初始化连接时开启promise模式:const db = mysql.createPool(...).promise(); exports.isLoggedIn = async (req, res, next) => { if (!req.cookies.jwt) return next(); try { const decoded = await promisify(jwt.verify)(req.cookies.jwt, process.env.JWT_SECRET); const [userResult] = await db.query("SELECT * FROM user WHERE id = ?", [decoded.id]); if (!userResult.length) return next(); const currentUser = userResult[0]; const [orderResult] = await db.query("SELECT * FROM orders WHERE email = ?", [currentUser.email]); currentUser.orders = orderResult || []; req.user = currentUser; next(); } catch (error) { next(); } };
2. 补全/profile路由的兜底逻辑
原路由只处理了req.user存在的场景,未登录时会出现无响应问题,修正后:
router.get("/profile", authController.isLoggedIn, (req, res) => { if (!req.user) { // 未登录时按业务需求处理,比如重定向到登录页 return res.redirect("/login"); } res.render("profile", { user: req.user }); });
3. 模板侧可选优化
给订单判断增加空值兜底,避免极端情况下访问undefined属性报错:
<div class="order-info-content"> {{#if user.orders.[0].id}} <div class="order-text"> <h4>{{user.orders.[0].date}}</h4> <h4>ID: #{{user.orders.[0].id}}</h4> <h4>Total: £{{user.orders.[0].total}}</h4> </div> <div class="order-images"> <img id="order-image" src="/Images/price 2.jpg" alt=""> </div> {{else}} <h4>You do not have any recent orders</h4> <br> <a href="" id="account-info-edit">View our latest competitions!</a> <br> {{/if}} </div>
调整后只要后端保证user.orders永远是数组类型,原有if+unless判断逻辑也可以正常运行,不需要额外注册hbs helper。
内容的提问来源于stack exchange,提问作者Wild-tuna
相关产品推荐
相关产品推荐

