Node.js 应用的御用品: Node.js 错误处理系统

这篇具有很好参考价值的文章主要介绍了Node.js 应用的御用品: Node.js 错误处理系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

开发中,有些开发者会积极寻求处理错误,力求减少开发时间,但也有些人完全忽略了错误的存在。正确处理错误不仅意味着能够轻松发现和纠正错误,而且还意味着能够为大型应用程序开发出稳健的代码库。

特别是对于 Node.js 开发人员,他们有时会也发现自己使用了不那么整洁的代码来处理各种错误,例如会在所有地方都用相同的逻辑来处理错误。那么,难道 Node.js 在处理错误方面不太友好 ?

不。本文里,我想告诉的是 Node.js 一点问题也没有。

Node.js 错误处理之错误类型

首先,我们有必要对 Node.js 中的错误有一个清晰的认识。一般来说,Node.js错误分为两大类: 操作错误 和 开发者错误。

  • 操作错误:表示运行时问题,其结果是预期的,应该以适当的方式处理。操作错误并不意味着应用程序本身有错误,但开发者需要仔细处理它们。操作错误的例子包括“内存不足”、“API 参数的无效输入”等等。
  • 开发者错误:是指在写得不好的代码中出现了意想不到的错误。意思就是代码逻辑本身有一些问题,需要解决。一个很好的例子是尝试读取 “undefined” 的属性。要解决这个问题,必须更改代码。因为这是开发者制造的错误,而不是操作错误。

接下来的一个问题是:“为什么我们要把它们分成两类来处理?”

原因是,如果你没有对错误有一个清晰的认识,那么每当出现错误时,你可能会想重启服务。而当成千上万的用户正在使用你的程序时,他们可能看到的是“Not Found”。那这样的重启是否有意义?

同样,如果你的代码逻辑发生错误的时候,给应用带来了意想不到的问题,影响到了用户体验,这是否有意义?

正确处理错误

假设你有一些使用异步 Js 的经验,那么在使用回调处理错误时可能会遇到一些挑战。例如在回调函数中你不断地进行错误检查,可能会导致嵌套过深,从而引发“回调地狱”的问题。这种情况会使代码流变得难以跟踪和理解。

那么,你可以使用 promise或async/await 替代回调。例如下面这段代码:

const doAsyncJobs = async () => {
 try {
   const result1 = await job1();
   const result2 = await job2(result1);
   const result3 = await job3(result2);
   return await job4(result3);
 } catch (error) {
   console.error(error);
 } finally {
   await anywayDoThisJob();
 }
}

在 Node.js 中有一个内置的 Error 对象,也是一个很好的处理办法,因为它包含了直观而清晰的错误信息,比如 StackTrace,大多数开发者都依赖它来跟踪错误的根源。除此之外,还有一些其他有意义的属性,如 HTTP 状态码和通过扩展 Error 类的描述,将使其错误描述的更加具体。

class BaseError extends Error {
 public readonly name: string;
 public readonly httpCode: HttpStatusCode;
 public readonly isOperational: boolean;
 
 constructor(name: string, httpCode: HttpStatusCode, description: string, isOperational: boolean) {
   super(description);
   Object.setPrototypeOf(this, new.target.prototype);
 
   this.name = name;
   this.httpCode = httpCode;
   this.isOperational = isOperational;
 
   Error.captureStackTrace(this);
 }
}

//继承 BaseError
class APIError extends BaseError {
 constructor(name, httpCode = HttpStatusCode.INTERNAL_SERVER, isOperational = true, description = 'internal server error') {
   super(name, httpCode, isOperational, description);
 }
}

为了简单起见,我只实现了一些 HTTP 状态码,你可以尝试添加更多状态码:

export enum HttpStatusCode {
 OK = 200,
 BAD_REQUEST = 400,
 NOT_FOUND = 404,
 INTERNAL_SERVER = 500,
}

同时,你可以根据你的需要和个人偏好对常见错误进行扩展:

class HTTP400Error extends BaseError {
 constructor(description = 'bad request') {
   super('NOT FOUND', HttpStatusCode.BAD_REQUEST, true, description);
 }
}

那么如何使用它呢? 很简单,就是抛出这种错误类型:

const user = await User.getUserById(1);
if (user === null)
 throw new APIError(
   'NOT FOUND',
   HttpStatusCode.NOT_FOUND,
   true,
   'detailed explanation'
 );

集中式 Node.js 错误处理组件

现在,我们准备构建 Node.js 错误处理系统的主要组件: 集中式错误处理组件。

构建集中式的错误处理组件通常是一个好主意,以便在处理错误时避免可能的代码重复。错误处理组件负责使捕获的错误变得可以理解,例如,通过向系统管理员发送通知、将事件传输到监视服务器中(如 Sentry)、打日志记录错误。

下图中我给出了处理错误的基本工作流程:

Node.js 应用的御用品: Node.js 错误处理系统,服务端语言,node.js

在代码的某些部分,错误会被捕获并传递给错误处理中间件:

try {
 userService.addNewUser(req.body).then((newUser: User) => {
   res.status(200).json(newUser);
 }).catch((error: Error) => {
   next(error)
 });
} catch (error) {
 next(error);
}

错误处理中间件是区分错误类型并将它们发送到集中式错误处理组件的好地方:

app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {
 if (!errorHandler.isTrustedError(err)) {
   next(err);
 }
 await errorHandler.handleError(err);
});

到目前为止,你应该可以想象到集中式组件应该是什么样子。不过请记住,这完全取决于你如何实现它。例如,它可能看起来像以下这样:

class ErrorHandler {
 public async handleError(err: Error): Promise<void> {
   await logger.error(
     'Error message from the centralized error-handling component',
     err,
   );
   await sendMailToAdminIfCritical();
   await sendEventsToSentry();
 }
 
 public isTrustedError(error: Error) {
   if (error instanceof BaseError) {
     return error.isOperational;
   }
   return false;
 }
}
export const errorHandler = new ErrorHandler();

不过,有时候你会发现默认的 “console.error” 输出错误信息不是很好阅读。相反,以格式化的方式输出错误可能会更好,这样开发者可以更快速理解问题并确保它们得到修复。

这里,我向你推荐 winstonmorgan 这样的可定制记录器。

例如,下面是一个定制的 winston 记录器:

const customLevels = {
 levels: {
   trace: 5,
   debug: 4,
   info: 3,
   warn: 2,
   error: 1,
   fatal: 0,
 },
 colors: {
   trace: 'white',
   debug: 'green',
   info: 'green',
   warn: 'yellow',
   error: 'red',
   fatal: 'red',
 },
};
 
const formatter = winston.format.combine(
 winston.format.colorize(),
 winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
 winston.format.splat(),
 winston.format.printf((info) => {
   const { timestamp, level, message, ...meta } = info;
 
   return `${timestamp} [${level}]: ${message} ${
     Object.keys(meta).length ? JSON.stringify(meta, null, 2) : ''
   }`;
 }),
);
 
class Logger {
 private logger: winston.Logger;
 
 constructor() {
   const prodTransport = new winston.transports.File({
     filename: 'logs/error.log',
     level: 'error',
   });
   const transport = new winston.transports.Console({
     format: formatter,
   });
   this.logger = winston.createLogger({
     level: isDevEnvironment() ? 'trace' : 'error',
     levels: customLevels.levels,
     transports: [isDevEnvironment() ? transport : prodTransport],
   });
   winston.addColors(customLevels.colors);
 }
 
 trace(msg: any, meta?: any) {
   this.logger.log('trace', msg, meta);
 }
 
 debug(msg: any, meta?: any) {
   this.logger.debug(msg, meta);
 }
 
 info(msg: any, meta?: any) {
   this.logger.info(msg, meta);
 }
 
 warn(msg: any, meta?: any) {
   this.logger.warn(msg, meta);
 }
 
 error(msg: any, meta?: any) {
   this.logger.error(msg, meta);
 }
 
 fatal(msg: any, meta?: any) {
   this.logger.log('fatal', msg, meta);
 }
}
 
export const logger = new Logger();

它主要提供的是以格式化的方式在多个不同级别进行日志记录,颜色清晰,并根据运行时环境记录到错误日志文件中。这样做的好处是,你可以使用 winston 的内置 api 来监视和查询日志。此外,你可以使用日志分析工具来分析格式化的日志文件,以获得有关应用程序的更多有用信息。

到目前为止,我们主要讨论了如何处理操作错误,那开发者的代码逻辑造成的错误呢?

由于开发者的错误是意料之外的,它们是实际的 bug,可能导致应用程序最终处于错误的状态,并以意想不到的方式运行。那么,处理这些错误的最佳方法是“立即崩溃”,然后使用像 PM2这样的自动重启器优雅地重新启动:

process.on('uncaughtException', (error: Error) => {
 errorHandler.handleError(error);
 if (!errorHandler.isTrustedError(error)) {
   process.exit(1);
 }
});

最后我想要提到的是处理未处理的 promise.reject 和 异常。

在开发 Node.js/Express 应用程序时,你可能会发现自己花了很多时间处理承诺。当你忘记处理 reject 时,会看到有关未处理 promise.reject 的警告信息。

除了日志记录之外,警告消息不会做太多事情,但是使用适当的回退和订阅 process.on('unhandledRejection',callback) 是一个不错的做法。你可以将其视为Node.js 的一种全局的错误处理程序。

典型的错误处理流程如下所示:

User.getUserById(1).then((firstUser) => {
  if (firstUser.isSleeping === false) throw new Error('He is not sleeping!');
});
...
 
// 获取未处理的 reject 并将其扔给我们已有的另一个回退处理程序
process.on('unhandledRejection', (reason: Error, promise: Promise<any>) => {
 throw reason;
});
 
process.on('uncaughtException', (error: Error) => {
 errorHandler.handleError(error);
 if (!errorHandler.isTrustedError(error)) {
   process.exit(1);
 }
});

结尾

现在,你是否意识到无论是在开发阶段还是在生产阶段错误处理可不是一个可选的功能,而是应用程序的一个必要部分。

在 Node.js 中的单个组件中处理错误的策略将确保开发人员节省宝贵的时间,并通过避免代码重复和丢失错误上下文来编写干净且可维护的代码。不得不说,它已经成为 Node.js 应用程序的必备保健品。文章来源地址https://www.toymoban.com/news/detail-694820.html

到了这里,关于Node.js 应用的御用品: Node.js 错误处理系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Node.js】如何修复“错误:错误:0308010c:digital envelope routines::不受支持”

    作为一名开发人员,在项目中遇到错误是很常见的。在这篇博客文章中,我们将讨论一个困扰开发人员的特定错误,尤其是那些使用Node.js的开发人员。有问题的错误是“错误:错误:0308010c:数字信封例程::不受支持”,正如承诺的那样,我们将为您提供所有可能的修复方法

    2024年02月05日
    浏览(57)
  • window 10 安装node.js时遇到2502 2503错误(已解决)

    node安装失败2503的解决办法:1、在WIN搜索框搜索powershell并右击;2、点击使用管理员身份运行powershell命令行工具;3、输入“msiexec /package node”;4、打开安装包,根据提示安装即可。 本文操作环境:Windows7系统,nodejs10.16.2版,Dell G3电脑。 如何解决node 安装失败2503问题? Nod

    2023年04月27日
    浏览(61)
  • node.js下载和vite项目创建以及可能遇到的错误

    目录 一、node.js的下载 1、去官网下载   节点.js (nodejs.org) 2、下载过程 第一步: 第二步: 第三步: 第四步: 第五步: 二、vite项目的创建(使用的工具是Hbuilder x) 第一步:  出现报错 Need to install the following packages:  create-vite-app@1.21.0 第二步: 第三步:  三、可能出现的报

    2024年02月03日
    浏览(53)
  • VScode运行npm错误解决:如何安装与配置Node.js环境

    在VScode中遇到npm无法识别的错误时,可能是因为未安装Node.js或环境变量配置不正确。

    2024年02月06日
    浏览(94)
  • 【Node.js】path 模块进行路径处理

    Node.js 执行 JS 代码时,代码中的路径都是以终端所在文件夹出发查找相对路径,而不是以我们认为的从代码本身出发,会遇到问题,所以在 Node.js 要执行的代码中,访问其他文件,建议使用绝对路径 实例: 问题原因:就是从代码文件夹出发,使用 ../text.txt 解析路径,找不到

    2024年02月20日
    浏览(50)
  • 使用ExcelJS快速处理Node.js爬虫数据

    ExcelJS是一个用于处理Excel文件的JavaScript库。它可以让你使用JavaScript创建、读取和修改Excel文件。 以下是ExcelJS的一些主要特点: 支持xlsx、xlsm、xlsb、xls格式的Excel文件。 可以创建和修改工作表、单元格、行和列。 可以设置单元格样式、字体、背景颜色等。 可以设置工作表的

    2024年02月03日
    浏览(46)
  • node.js系列-常见问题处理方案(持续更新)

    `` 浏览器中我们可以这样使用: node.js中实现方案 解决方案: 修改eslint配置文件 , 举个栗子:.eslintrc.js 使用方案 今天就写到这里啦~ 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦~~ 大家要天天开心哦 欢迎大家指出文章需要改正之处~ 学无止境,合作共赢 欢迎路过

    2024年02月14日
    浏览(45)
  • 【Express.js】全局错误处理

    在前面几节里,我们处理异常的方法都是手动在可能引发异常的地方捕捉错误,这固然是必要的,可以有针对性得处理异常,但很多时候,有许多潜在的异常,有一句话叫永远不要相信输入的数据,你永远都不知道什么时候可能会以什么方式触发某些阴间异常从而造成系统崩

    2024年02月10日
    浏览(46)
  • cool 中的node.js 实现一个处理第三方Api 数据的处理

    1.需求     你现在是一个后端 前端跟你要一个接口 ,但是你发现 你这个接口 除了调用第三方Api的接口 有的数据还是没有 你直接返回 前端使用不了 因为都没有关于那样的数据 但是三方Api 中有其他的接口和现在的接口 经过处理 是可以实现这个前端需要的数据。遇到这样的

    2024年01月19日
    浏览(43)
  • 解决node.js-opensslErrorStack: [ ‘error:03000086:digital envelope routines::initialization error‘ ]错误

    详细错误提示如下: 1-出现这个错误原因:因为我之前是node16更新到18后出现这个查了很多资料才知道node高版本加入了更严格的限制。 2-在项目的package.json文件下更改scripts加上这行代码SET NODE_OPTIONS=--openssl-legacy-provider 截图如下: 3-重新运行npm run dev命令行完美解决这个问题

    2024年02月13日
    浏览(106)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包