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

在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)

解决方案

问题根源

  1. 代码中console.trace(error)使用了未定义的变量error,正确变量应为err或newError,这导致输出错误的堆栈信息。
  2. 手动创建新的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 11:01:06