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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:18:54