写点什么

入门 Node.js 处理错误

用户头像
废材壶
关注
发布于: 5 小时前
入门Node.js 处理错误

前言

一个健壮性的 Node.js 项目,需要处理好程序错误,本文将带你入门 Node.js 的错误处理。

Error 基础

Node.js 中的错误是 Error 类的任何实例,包括一些内置错误类,还可以扩展基本 Error 类,内置错误类或其他自定义错误来创建用户定义的错误。

JavaScript Error 标准类

new Error([message[, fileName[, lineNumber]]])
复制代码
  • message: 描述错误的信息

  • fileName: Error 代码所在的文件名

  • lineNumber: 调用 Error 构造器所在的文件的行号

const myError = new Error('some error happened')console.log(myError.message) // some error happenedconsole.log(myError.name) // Errorconsole.log(myError.stack) // 'Error: some error happened\n    at <anonymous>:1:17'  
复制代码

除通用 Error 外,JavaScript 还有 6 个其他类型的内置错误对象

  • EvalError: 表示 eval() 有关的错误原因

  • InternalError: 表示JavaScript引擎内部异常错误

  • RangeError: 表示数值变量或参数超出有效范围错误

  • ReferenceError: 表示引用错误

  • SyntaxError: 表示语法错误

  • TypeError: 表示变量或参数类型错误

  • URIError: 表示给 encodeURI()decodeURI()传递的参数无效

这些 Error 对象一旦你抛出它,它就会在堆栈中冒泡,直到在某个地方被捕获到,如果没有捕获到它,它将会变成一个未捕捉到的异常,这可能会导致你的 Node.js 应用程序崩溃。

我们常会遇到的错误类型,往往都是以下的几种情况

  • JavaScript 标准错误

  • 底层操作系统引发的系统错误

  • 应用程序代码触发的用户指定的错误

  • assert 断言模块引发的错误

错误处理

同步错误

Node.js 中发生的同步错误,都可以使用 throw 抛出错误,使用 try/catch 捕获错误,如果没有捕获错误,它将向上冒泡,变成 uncaughtException,从而导致应用程序退出。

异步错误

  1. 使用 callback 这种错误优先的回调函数方式,会将错误作为第一参数传递给回调函数。这种错误不能使用try/catch 捕获

fs.readFile('a file that does not exist', (err, data) => {  if (err) {    console.error('There was an error reading the file!', err);    return;  }})
复制代码
  1. EventEmitter 对象引发的错误,会传递到对象的'error'事件中处理,如果对象没有绑定对应事件,则将错误抛出,错误会冒泡到 process.uncaughtException 捕获。这种错误不能使用 try/catch 捕获

  2. 更现代化的异步 Promise,任何利用错误优先回调进行异步错误的 Node.js API 都可以使用内置的util.promisify() 方法转为 promise。 Promise 链的错误会在 catch 方法上捕获,如果没有 catch,错误会一直冒泡到顶层,在 process.unhandleRejection 上捕获

错误分类

错误分类广泛的区分有 操作错误开发者错误

操作错误

操作错误,是在程序运行时发现的错误。操作错误不是错误,可能会不时发生,主要是由于一种或多种外部因素的组合,例如数据库服务器超时或用户决定通过在输入字段中输入 SQL 查询来尝试进行 SQL 注入这种情况,需要正确处理,避免导致更严重的问题。例如:

  • 网络连接故障

  • API 请求因某种原因失败

  • 内存溢出

  • 请求超时

  • 无法连接数据库

  • 等等

这种操作错误多数是可预测到的,处理错误

  • 将错误向上报告堆栈,例如 throw 抛出等方式

  • 重试。一些网络请求有时会失败,重试有时会有作用。

  • 有一些崩溃类的错误,会导致程序终止,需要通过日志记录这种错误,便于排查问题并修复它。

开发者错误

这类错误大多情况是开发人员书写的程序逻辑或语法中的错误,这种错误是可以通过源代码更改避免问题的。例如

  • 语法错误

  • 代码逻辑不够严谨

  • 函数参数错误

  • 等等

扩展错误

业务需求开发中,有时你需要扩展错误类,方便业务记录错误日志消息等。需要基于 Error 做一些封装。例如:

  • ApplicationError 这是所有其他错误类的基类,即所有其他错误类都继承自它

  • DatabaseError 与数据库操作相关的任何错误都将从此类继承。

例如:

class ApplicationError extends Error {  get name() {    return this.constructor.name;  }}
class DatabaseError extends ApplicationError {}
class UserFacingError extends ApplicationError {}
module.exports = {    ApplicationError,    DatabaseError,    UserFacingError,}
复制代码

这种方法使我们能够区分应用程序抛出的错误。所以现在如果我们要处理错误的请求错误(无效的用户输入)或未找到的错误(未找到资源),我们可以从 UserFacingError 基类继承(如下面的代码所示)

const { UserFacingError } = require('./baseErrors')
class BadRequestError extends UserFacingError {    constructor(message, options = {}) {        super(message);
        for (const [key, value] of Object.entries(options)) {            this[key] = value;        }    }
    get statusCode() {        return 400;    }}

class NotFoundError extends UserFacingError {    constructor(message, options = {}) {        super(message);        for (const [key, value] of Object.entries(options)) {            this[key] = value;        }    }    get statusCode() {        return 404    }}
module.exports = {    BadRequestError,    NotFoundError}

复制代码

错误日志

所有的生产项目,应该都需要有对应的持久化错误日志,记录信息便于追踪、排查错误原因。

常用库有 log4jswinston,下面以log4js作为使用例子

const log4js = require('log4js');
const logger = log4js.getLogger();logger.level = 'debug';
logger.info('Log debug start');

复制代码


上面只是在控制台打印了日志,生产项目需要保存日志到本地,详细可以查看 log4js 文档。

总结

本文主要是简单介绍了 Node.js 开发中对于错误的处理。对于业务层的错误抽象还可以更复杂些,避免在业务代码重复写 try/catch 等错误处理逻辑。

行文仓促,如果文中有表述不准确的地方,欢迎指正。


我是废材壶,前端开发者,欢迎微信搜一搜「 CodeLife 集」阅读不迷路

参考

发布于: 5 小时前阅读数: 6
用户头像

废材壶

关注

还未添加个人签名 2018.06.09 加入

我是废材壶,前端开发者,欢迎微信搜一搜「 CodeLife集」阅读不迷路

评论

发布
暂无评论
入门Node.js 处理错误