Mongoose findById在Auth中间件中无法执行的问题求助
看起来你遇到的核心问题是: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

