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

Node.js Express/Mongoose场景下错误处理中间件无法获取控制器抛出错误的完整属性

问题根因
  1. 错误处理中间件中使用let error = { ...err }浅拷贝错误对象时,原生Error对象的核心属性(name/message/stack)属于不可枚举属性,对象扩展运算符只会复制可枚举的自有属性,因此拷贝后的对象会丢失这些属性。
  2. 你当前在控制器的catch块中,无论捕获到什么错误,都直接封装成了自定义的ErrorResponse实例传给next,如果你的自定义错误类没有正确挂载name属性,也会导致错误处理中间件读取不到该属性。

解决方案

1. 修复错误处理中间件的取值逻辑

不要直接用扩展运算符拷贝错误对象,直接从原始err对象上读取属性即可,修改后的代码如下:

const errorHandler = (err, req, res, next) => {
  console.log(`Error in method:${req.method}: ${err.stack}`.bgRed);

  // 直接从原始err取值,避免丢失不可枚举属性
  const statusCode = err.statusCode || 500;
  const message = err.message || 'Server Error';
  console.log(`Error handler: ${err.name}`);

  res.status(statusCode).json({
    success: false,
    data: message,
  });
};

module.exports = errorHandler;

如果确实需要拷贝错误对象做修改,手动补充不可枚举属性即可:

let error = {
  ...err,
  name: err.name,
  message: err.message,
  stack: err.stack
};

2. 确保自定义ErrorResponse类实现正确

检查你utils/error.js中的ErrorResponse类是否正确继承Error并挂载name属性,标准实现参考:

class ErrorResponse extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
    // 手动设置错误类型名
    this.name = 'ErrorResponse';
    // 保留正确的栈追踪
    Error.captureStackTrace(this, this.constructor);
  }
}

module.exports = ErrorResponse;

3. 按需保留原始错误信息

如果你需要在错误处理中间件中判断原生错误类型(比如Mongoose的CastError/ValidationError等),不要在catch块中直接把所有错误都封装成ErrorResponse,可以判断错误类型后再处理,保留原始错误的属性:

catch (err) {
  console.log(err.name);
  console.log('ERROR APPEND');
  // 针对特定错误类型返回自定义提示
  if(err.name === 'CastError') {
    return next(new ErrorResponse(`Product not found with id:${req.params.id}`, 404));
  }
  // 其他错误直接传递,保留原始属性
  next(err);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 00:15:07