我正在开发一个新项目,它将提供可以安装的多个不同(可选)软件包,所有这些软件包都是核心软件包(仅手动软件包)的补充。其他包只与核心进行交互。
该项目只是为了跟踪数据列表(我知道不是非常具体,但不需要这些细节)。附加软件包确定数据列表如何与之交互。 核心包只包含所有主要的JS功能和数据库模型以及身份验证。其他包与这些相关。
这些插件包我称之为“facade”包。您真正需要从上面推断的是核心是与 facade 包相对应的独立包,它处理核心功能(数据库内容,身份验证,授权等)
核心可以使用promises或callbacks,并返回失败的异常,然后用于与核心交互的任何facade包将处理异常/错误(显示HTTP错误页面,返回RESTful错误结果等。)
由于处理错误的包与返回错误的包不同,因此需要系统地了解返回错误的 type ,因此可以正确处理(EG:webui / restui包应该知道它是否需要显示HTTP 500,HTTP 403,HTTP 409等)。显然核心只返回new Error('Something broke')
,然后外观包并不真正知道它是什么类型的错误,除非他们将文本保存在某处并且可以将其与错误代码匹配。
最好的方法是什么?我找不到任何可以完全符合我想要的东西..
我最终开始自己的尝试..(下)
我创建了一个新的AppError
异常类型,而不是使用简单字符串返回AppError
个异常,而是提供错误代码,它会将该异常与错误消息相关联,错误类型等。
以下是AppError
例外的示例用法:
exports.createThing = ( name, data ) => {
return new Promise( ( res, rej ) => {
if( doesItExist( name ) )
return rej( new AppError( 'document.create.duplicateName' ) )
// Other stuff...
})
}
现在在AppError
异常方法中,它需要code
并查看异常列表(code
应该是异常数据对象中的键)。
以下是上述异常的异常数据对象包含的示例:
module.exports = {
'document.create.duplicateName': {
type: 'DocumentConflict',
message: 'Failed to create new document',
detail: 'The document name specified already exists, try another one'
}
}
使用示例:假设我们尝试使用已存在的createThing
(来自name
包中)执行webui
:
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 Conflict)。显然,这些关联可以保存在一个对象中,这样可以很容易地为返回的任何错误type
值检索正确的错误代码。然后,错误代码的文本就在err.message
和err.detail
这也使得在应用程序中引入某种类型的语言环境变得容易,因为错误,因为所有需要做的就是编辑异常数据对象。
因此,如果您认为我的解决方案是充分的,并且您无法想到任何问题,那么请说出来。我想知道它是否或不是。即使你不能想出一个合适的解决方案,但你只知道我创建的那个不会工作,也要分享它。
如果您有替代解决方案,那么这也会起作用!
由于
答案 0 :(得分:1)
我认为有两种基本方法可以解决这个问题:
code
属性:创建一个新的\Error
对象,并为代码属性分配有关错误的信息。例如:
var err = new Error('Message');
err.code = "DocumentConflict";
自定义错误对象。您可以为每种错误类型分配一个单独的Error对象。例如,您可能会遇到AppError
错误,而不仅仅是DocumentConflict
。
对于我正在创建RESTful API的项目,我喜欢考虑错误代码。对于大多数项目,端点将返回以下代码之一:
然后,这些将成为我在应用程序中传递的“标准”错误类型。普通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")
对象。要检查对象的类型,可以使用instanceof
。例如,使用Express,您可以使用类似于以下内容的错误处理程序:
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"
});
}
});
值得注意的是,您可以定义自定义错误对象构造函数,而不仅仅是字符串。例如,您可以将对象传递给BadRequestError
构造函数以提供字段级错误详细信息。
现在,在大多数情况下,您可以传播错误,并且对端点的响应也是有意义的。但是,有些情况下您希望转换错误类型。例如,如果您有登录端点,则可以向findUserByEmailAddress()
发出请求。这可能会返回NotFoundError对象,但您希望在signIn()
函数中捕获它并将其转换为CredentialsError。