在catchAsync函数中捕获完整堆栈跟踪,定位出错的中间件/端点
如何在Express的catchAsync工具中获取完整错误堆栈跟踪?
项目结构与代码示例
server.js
//server.js var express = require('express'); var app = express() // Error Handler Controller const globalErrorHandler = require('./controllers/error.controller'); // Import routes const emailsRoutes = require('./routes/emails.routes') const notificationsRoutes = require('./routes/notifications.routes') const reportsRoutes = require('./routes/reports.routes') const systemRoutes = require('./routes/system.routes') const siteRoutes = require('./routes/sites.routes') const accessRoutes = require('./routes/access.routes') // etc ... app.use('/v1/emails' ,emailsRoutes) app.use('/v1/notifications', notificationsRoutes) app.use('/v1/reports', reportsRoutes) app.use('/v1/system', systemRoutes) app.use('/v1/sites', siteRoutes) app.use('/v1/access', accessRoutes) // Add this AFTER all your routes app.use(globalErrorHandler);
路由文件(以emails.routes.js为例)
const emailsRouter = require("express").Router(); const { userValidation } = require("../middleware/Permissions"); const { getEmailGroupsForConfig, postEmailGroupsForConfig, updateEmailGroupsForConfig } = require("../controllers/email.controller"); emailsRouter.use(userValidation()); emailsRouter.get("/groups", getEmailGroupsForConfig); emailsRouter.post("/groups", postEmailGroupsForConfig); emailsRouter.put("/groups", updateEmailGroupsForConfig); module.exports = emailsRouter;
控制器文件(以email.controller.js为例)
'use strict' const catchAsync = require("../utils/catchAsync"); const { vmsfull_dbc, replica_dbc } = require("../database_connection"); const AppError = require("../utils/appError"); exports.getEmailGroupsForConfig = catchAsync(async (req, res) => { if (!req.user.checkUserPermission('write-email-groups')) { return next( new AppError("Unauthorized", 403)); } let sql_query = 'SELECT * from vms_metadata."email_groups" ORDER BY group_name ASC'; const emailGroupe = await vmsfull_dbc.query(sql_query); return res.status(200).send(emailGroupe.rows); });
当前的catchAsync工具函数
module.exports = fn => { return (req, res, next) => { fn(req, res, next).catch(err => { // Preservar el stack trace original const newError = new Error(err.message); newError.statusCode = err.statusCode || 500; newError.status = err.status || 'error'; newError.stack = err.stack; // Preservar el stack trace original console.error(newError); // Imprimir el error console.trace(error); // Imprimir el stack trace completo next(newError); }); }; };
问题描述
目前能检测到错误,但执行console.trace(error)时仅输出catchAsync.js文件的堆栈信息,无法定位到具体出错的中间件或端点:
Trace: [Error] at C:\My\Path\Directory\server\src\utils\catchAsync.js:22:15 at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
解决方案
问题根源
- 代码中
console.trace(error)使用了未定义的变量error,正确变量应为err或newError,这导致输出错误的堆栈信息。 - 手动创建新的
Error对象会丢失原错误的上下文关联,即使赋值了stack也无法完整保留原始调用链。
修改后的catchAsync函数
module.exports = fn => { return (req, res, next) => { fn(req, res, next).catch(err => { // 为错误补充默认属性(仅当原错误未定义时) err.statusCode = err.statusCode || 500; err.status = err.status || 'error'; // 输出完整错误信息与原始堆栈 console.error('错误详情:', err); console.trace('错误追踪:', err); // 传递原始错误给全局错误处理器 next(err); }); }; };
说明
- 直接复用原始错误对象
err,可以完整保留错误发生时的调用堆栈,包括控制器、中间件等源头位置。 - 修正了
console.trace的变量名错误,确保输出实际捕获到的错误信息。 - 仅在原错误缺少必要属性时补充默认值,避免破坏原始错误的完整性。
内容的提问来源于stack exchange,提问作者Raul Andrade
相关产品推荐
相关产品推荐

