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

向Pug模板传递用户数据时遇TypeError: req.next不是函数问题求助

问题分析与解决方案

错误根源

你遇到的TypeError: req.next is not a function是因为中间件isLoggedIn中多次调用next(),且异步操作与同步逻辑的执行顺序混乱,导致Express请求生命周期被破坏,req对象的next方法失效。具体问题点:

  • 外层if (req.cookies.jwt)块末尾,会在异步数据库查询完成前执行next(),之后异步回调里又再次调用next(),同一个请求多次推进生命周期。
  • 数据库查询结果判断错误:result == 0不严谨,mysql查询返回的是数组,应该用result.length === 0。
  • 用户赋值错误:result是查询结果数组,直接取result.id会得到undefined,需用result[0].id。

修正后的代码

1. 修复isLoggedIn中间件

将回调式数据库操作改为Promise形式,确保next()只在合适时机调用一次:

const { promisify } = require('util');
// 先将数据库方法转为Promise格式,避免回调嵌套
const getConnection = promisify(db.getConnection).bind(db);

exports.isLoggedIn = async (req, res, next) => {
  if (req.cookies.jwt) {
    try {
      // 验证JWT
      const decoded = await promisify(jwt.verify)(
        req.cookies.jwt,
        process.env.JWT_SECRET
      );

      // 获取数据库连接并查询用户
      const connection = await getConnection();
      const sqlSearch = "SELECT * FROM users WHERE id = ?";
      const search_query = mysql.format(sqlSearch, [decoded.id]);
      // 手动promisify query方法
      const query = promisify(connection.query).bind(connection);
      const result = await query(search_query);
      connection.release();

      if (result.length === 0) {
        return next();
      }

      // 用户存在,赋值给req和模板变量
      req.user = result[0].id;
      res.locals.user = result[0].id;
      return next();

    } catch (err) {
      // JWT验证失败或数据库错误,直接推进流程
      return next();
    }
  }
  // 无JWT时推进流程
  next();
};

2. 优化getCourses控制器(可选)

查询不到课程时,渲染404模板而非返回JSON,保持前后端逻辑一致:

exports.getCourses = async (req, res, next) => {
  try {
    const connection = await getConnection();
    const sqlSearch = "Select * from courses";
    const search_query = mysql.format(sqlSearch);
    const query = promisify(connection.query).bind(connection);
    const result = await query(search_query);
    connection.release();

    if (result.length === 0) {
      return res.status(404).render("404", {
        title: "暂无课程"
      });
    }

    res.status(200).render("courses", {
      title: "Courses we offer",
      courses: result,
    });
  } catch (err) {
    next(err); // 将错误传递给Express内置错误处理中间件
  }
};

关键注意事项

  • 禁止在异步回调中重复调用next(),确保每个请求仅调用一次next()。
  • 使用async-await替代嵌套回调,避免回调地狱导致的流程混乱。
  • 数据库操作完成后必须释放连接,防止连接池耗尽。

内容的提问来源于stack exchange,提问作者Szymon Tymuła

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:05:43