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

Mongoose findById在Auth中间件中无法执行的问题求助

解决Mongoose在Auth中间件中findById不执行的问题

看起来你遇到的核心问题是:Mongoose查询在JWT验证的异步回调里完全没有执行,连调试日志都没有输出。结合你的代码和描述,我觉得有两个最可能的原因,咱们一个个来解决:

1. Mongoose连接未就绪时就处理请求

你的index.js里直接启动了服务器,没有等待Mongoose连接完全建立。虽然server.listen回调里的sanity check能正常运行(因为服务器启动后,连接大概率已经建立了),但如果请求在Mongoose连接完成之前就进来了,查询就会被挂起,不会有任何输出。

解决方案:等Mongoose连接成功后再启动服务器

修改index.js里的服务器启动逻辑,把server.listen放到Mongoose的open事件回调里:

// ... 之前的代码保持不变 ...

mongoose.connection.on('open', function() {
  console.log('MongoDB 连接成功!');
  // 连接就绪后再启动服务器
  server.listen(8080, function(){
    console.log('%s listening at %s', "OneBoard Server", server.url);
    // 在这里执行sanity check,确保连接正常
    one.model.User.findById('5b0b256b044e0e0274b4367c')
      .then(user => console.log('Sanity check用户:', user))
      .catch(error => console.log('Sanity check失败:', error));
  });
});

这样就能保证所有请求进来的时候,Mongoose已经和MongoDB建立好连接,查询不会因为连接未就绪而被挂起。

2. Restify中间件未处理异步流程,导致请求提前结束

你的Auth中间件里,jwt.verify是异步操作,而且里面的findById也是异步的,但你没有调用next()或者breakChain()来通知Restify异步操作完成。Restify会认为中间件已经执行完毕,提前结束请求,进而导致Mongoose的查询被取消,自然没有调试日志和结果输出。

解决方案:在异步操作完成后调用中间件流程方法

修改AuthMiddleware.js的exec方法,在findById的结果返回后,调用next()(认证成功)或者breakChain()(认证失败):

const Middleware = require('../lib/routing/Middleware')
const jwt = require('jsonwebtoken')
const authHelper = require('auth-header')
const config = require('../config.js')

class AuthMiddleware extends Middleware {
  exec( req, res, breakChain, next ){
    const auth = authHelper.parse(req.header('authorization'))
    jwt.verify( auth.token, config.auth.jwtSecret, ( error, decoded ) => {
      if (error) {
        // JWT验证失败,直接中断请求链
        console.log('JWT验证失败:', error);
        return breakChain(new Error('Authentication failed'));
      }
      
      console.log('解码后的JWT:', decoded)
      console.log('用户ID:', {_id: decoded.id})
      console.log('findById方法存在:', !!one.model.User.findById)

      one.model.User.findById(decoded.id)
        .then(user => {
          console.log('查询到的用户:', user);
          // 把用户信息挂载到req上,方便后续控制器使用
          req.user = user;
          // 通知Restify继续执行后续路由
          next();
        })
        .catch(error => {
          console.log('查询用户失败:', error);
          // 查询失败,中断请求链
          breakChain(error);
        })
      
      console.log('post MW')
    })
  }
}

module.exports = AuthMiddleware

如果喜欢用async/await,代码会更清晰:

class AuthMiddleware extends Middleware {
  exec( req, res, breakChain, next ){
    const auth = authHelper.parse(req.header('authorization'))
    // 把回调改成async函数
    jwt.verify( auth.token, config.auth.jwtSecret, async ( error, decoded ) => {
      if (error) {
        console.log('JWT验证失败:', error);
        return breakChain(new Error('Authentication failed'));
      }
      
      console.log('解码后的JWT:', decoded)
      console.log('用户ID:', {_id: decoded.id})
      console.log('findById方法存在:', !!one.model.User.findById)

      try {
        const user = await one.model.User.findById(decoded.id);
        console.log('查询到的用户:', user);
        req.user = user;
        next();
      } catch (error) {
        console.log('查询用户失败:', error);
        breakChain(error);
      }
      
      console.log('post MW')
    })
  }
}

这样修改后,Restify会等待你的异步查询完成,Mongoose也会正常发送查询请求,调试日志应该就能正常输出了。

额外优化建议

你的models.js里,clips字段用了type: [],这在Mongoose里属于混合类型,可能会导致后续操作出现意外行为。建议明确指定数组的元素类型,比如如果是存储Clip的ObjectId,可以写成:

clips: { 
  type: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Clip' }], 
  default: [] 
}

如果是存储字符串,就写成type: [String],这样Mongoose会帮你做类型校验,避免潜在的问题。

内容的提问来源于stack exchange,提问作者garrettmills

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:37:11