需要系统地处理NodeJS项目中的错误/exception/拒绝

背景信息

我有一个新的项目,我将会提供可以安装的多个不同的(可选的)软件包,除了核心软件包(只有手册软件包)之外,所有这些软件包都可以被安装。 其他软件包只是与核心进行交互。

该项目只是为了跟踪数据列表(不是很具体,我知道,但这些细节是不需要的)。 附加软件包确定数据列表如何与之交互。 核心包只包含所有主要的JSfunction和数据库模型以及authentication。 其他的包裹和那些捆绑在一起。

  • 比方说,你只想把它作为一个标准的网页,你可以安装webui包,这将绑定到核心 ,并创build一个web应用程序
  • 如果你想创build一个API,你可以安装restapi包,它创build了RESTful接口; 您也可以安装spaui包,它将与RESTful接口进行交互,该接口从核心获取数据

这些插件包我会叫“外观”包。 所有你真正需要从上面推断出来的是核心是一个独立的包装外观包,它处理的核心function(数据库的东西,authentication,授权等)

问题

核心可以使用promises或callback函数,并且返回失败的exception,然后使用任何Facade包与核心交互将处理exception/错误(显示HTTP错误页面,返回RESTful错误结果等)。

由于处理错误的包不同于返回错误的包,因此需要有一个系统的方法来知道返回的错误types ,因此可以正确处理(EG:webui / restui包应该知道如果需要显示HTTP 500,HTTP 403,HTTP 409等)。 显然核心只是返回new Error('Something broke') ,那么外观包并不真正知道它是什么types的错误,除非他们把文本保存在某个地方,并且可以与错误代码相匹配。

什么是处理这个最好的方法? 我一直无法find任何完成这个我想要的东西..

我最终开始了自己的尝试..(下图)

我的可能的解决scheme(如果这是足够的,只需确认)

我创build了一个新的AppErrorexceptiontypes,而不是用简单的string返回AppErrorexception,而是提供一个将该exception与错误消息,错误types等关联的错误代码

这是一个AppErrorexception的例子:

 exports.createThing = ( name, data ) => { return new Promise( ( res, rej ) => { if( doesItExist( name ) ) return rej( new AppError( 'document.create.duplicateName' ) ) // Other stuff... }) } 

现在在AppErrorexception方法中,它接受code并查看exception列表( code应该是exception数据对象中的关键字)。

下面是exception数据对象的一个​​例子,上面的exception将包含:

 module.exports = { 'document.create.duplicateName': { type: 'DocumentConflict', message: 'Failed to create new document', detail: 'The document name specified already exists, try another one' } } 

示例用法 :假设我们尝试使用已经存在的name (从createThing包中)执行createThing

 CorePackage.createThing( 'foobar', 'some data' ) .catch( err => { /* The err is now an instance of AppError err.type -> DocumentConflict err.message -> Failed to create new document err.detail -> The document name specified already exists, try another one */ }) 

从这里开始,就像将err.type值与合适的HTTP错误代码关联起来一样简单! (这可能是HTTP 409冲突)。 显然,这些关联可以保存在一个对象中,这样就可以轻松地为返回的任何错误type值检索正确的错误代码。 那么错误代码的文本就在err.messageerr.detail

这也使得向应用程序引入某种types的语言环境变得容易,因为所有需要做的事情就是编辑exception数据对象。

post结尾

所以,如果你认为我的解决scheme是一个足够的,你不能想到任何问题,那么请说出来。 我想知道它是否或不是。 即使你不能想出一个适当的解决scheme,但你只知道我创build的那个不会工作,分享这个。

如果你有一个替代解决scheme,那么这也是一样的!

谢谢

我认为有两个基本的方法可以解决这个问题:

  • code属性 :创build一个新的\Error对象,并为代码属性分配有关错误的信息。 例如:

     var err = new Error('Message'); err.code = "DocumentConflict"; 
  • 自定义错误对象 。 你可以有一个单独的错误对象,每个错误types,你有。 例如,而不是只有AppError ,您可以有DocumentConflict错误。

对于创buildRESTful API的项目,我喜欢根据错误代码进行思考。 对于大多数项目,端点将返回以下代码之一:

  • 400(坏请求)
  • 401(凭证错误)
  • 403(禁止)
  • 404(未find)。
  • 500内部服务器错误)。

然后,这些成为我在应用程序中传递的“标准”types的错误。 正常的Error对象被解释为内部服务器错误,所以这总是将500传递给端点。

例如,

 CredentialsError = function (message) { Error.call(this, arguments); Error.captureStackTrace(this, this.constructor); this.message = message; }; util.inherits(CredentialsError, Error); CredentialsError.prototype.name = "CredentialsError"; 

然后根据需要返回/抛出一个new CredentialsError("Invalid password")对象。 要检查对象的types,可以使用instanceof 。 例如,对于Express,可以使用类似于以下的error handling程序:

 app.use(function(err, req, res, next) { var status; if (err instanceof error.FieldError) { status = 400; } else if (err instanceof error.CredentialsError) { status = 401; /* etc */ } else { status = 500; } if (status !== 500) { res.status(status).send(JSON.stringify( err, null, 4 )); } else { // for 500, do not output the error! console.error(err.stack); res.status(500).send({ message: "Internal Server Error" }); } }); 

还值得注意的是,你可以定义你的自定义错误对象的构造函数不仅仅是string。 例如,您可以将对象传递给BadRequestError构造函数,以提供字段级别的错误细节。

现在,在大多数情况下,您可以传播错误,并且对端点的响应将有意义。 但是,有些情况下您想要转换错误的types。 例如,如果您有login端点,则可以请求findUserByEmailAddress() 。 这可能会返回一个NotFoundError对象,但是您想要在signIn()函数中捕获它并将其转换为CredentialsError。