三个错误处理中间件搭配try-catch仍无法阻止应用崩溃,求排查
问题描述
希望Node.js应用在出错时不崩溃,仅通过res.send返回错误信息,但当前配置未生效。已将错误中间件挂载在路由末尾,接口中也用了try-catch捕获异常,但应用仍会崩溃。
路由配置
router.post('/signUp',signupmiddlewere.signup2error,Routes.signUp) router.post('/login',Routes.login) router.post('/jwtverify',Routes.jwtverify) router.use(errormiddelware) router.use(usererrorFunction) router.use(regularerrorFunction)
/jwtverify接口代码
module.exports.jwtverify = async (req,res,next)=>{ try { const {jwt} = req.body let objectid = 1 JWT.verify(jwt, 'secret', function(err, decoded) { objectid = decoded.id._id }); let user = 0 await User.findOne({_id:objectid}).then((result)=>{ user = result }).catch((err)=>{ next(err) }) res.status(200).send({ status:'success', user:user }) } catch (error) { next(error) } }
错误处理中间件
- regularerrorFunction
const regularerrorFunction = (error,req,res,next)=>{ return res.json(error.message) } module.exports = regularerrorFunction
- errorFunction(返回500状态码)
const errorFunction = (error,req,res,next)=>{ return res.status(500).json(error.message) } module.exports = errorFunction
- usererrorFunction(返回400状态码)
const usererrorFunction = (error,req,res,next)=>{ return res.status(400).json(error.message) } module.exports = usererrorFunction
问题根源
JWT.verify回调中的未捕获错误
JWT.verify用的是回调模式,如果传入无效JWT,err触发后decoded会是undefined,此时直接访问decoded.id._id会抛出Cannot read properties of undefined (reading 'id')错误。这个错误发生在回调函数内部,不在外层try-catch的捕获范围内,也没有被处理,直接导致应用崩溃。错误中间件未发挥作用的核心原因
上述未捕获错误根本没传到错误中间件,自然无法通过中间件返回错误响应。另外多个错误中间件的执行顺序和逻辑也有优化空间——如果前一个中间件没有调用next(error),后续中间件不会执行。
修复方案
1. 处理JWT.verify的错误
把JWT.verify改成可被try-catch捕获的形式,有两种方式:
方案1:使用同步版本
// 替换原JWT.verify代码块 try { const decoded = JWT.verify(jwt, 'secret'); objectid = decoded.id._id; } catch (jwtErr) { next(jwtErr); return; // 提前终止,避免后续无效代码执行 }
方案2:Promise封装回调版本
// 先封装JWT.verify为Promise const verifyJWT = (token, secret) => { return new Promise((resolve, reject) => { JWT.verify(token, secret, (err, decoded) => { if (err) reject(err); else resolve(decoded); }); }); }; // 接口中使用await调用 const decoded = await verifyJWT(jwt, 'secret'); objectid = decoded.id._id;
两种方式都能让JWT验证的错误被外层try-catch捕获,再通过next(error)传递给错误中间件。
2. 优化错误中间件逻辑
多个错误中间件需要按优先级处理,只有当前中间件无法处理时,再调用next(error)传递给下一个。比如按错误类型区分返回状态码:
// 优化usererrorFunction:处理用户侧错误 const usererrorFunction = (error, req, res, next) => { if (['JsonWebTokenError', 'ValidationError', 'CastError'].includes(error.name)) { return res.status(400).json(error.message); } next(error); // 非用户错误,传递给下一个中间件 }; // 优化errorFunction:处理服务器内部错误 const errorFunction = (error, req, res, next) => { return res.status(500).json(error.message || '服务器内部错误'); }; // 调整路由中中间件顺序:先处理用户错误,再处理服务器错误,最后兜底 router.use(usererrorFunction); router.use(errorFunction); router.use(regularerrorFunction);
3. 补充async函数错误捕获
接口是async函数,await User.findOne()的catch已经把错误传给next(err),这部分没问题,但要确保所有异步操作的错误都被覆盖。
内容的提问来源于stack exchange,提问作者today
相关产品推荐
相关产品推荐

