似乎对此有很多不同的意见,而不是一种首选方法。这是我找到的一些信息以及我最终做了什么。
每个函数都会提出一个问题。如果给出的输入使该问题成为谬误,则抛出异常。使用返回 void 的函数很难画出这条线,但底线是:如果违反了函数对其输入的假设,它应该抛出异常而不是正常返回。
答案 1:
无论你做什么,一定要记录下来。我认为这一点比究竟哪种方法“最好”更重要。
答案 2:
如果你总是希望找到一个值,那么如果它丢失了就抛出异常。异常意味着存在问题。
如果值可能缺失或存在,并且两者都对应用程序逻辑有效,则返回 null。
更重要的是:你在代码的其他地方做了什么?一致性很重要。
应该在哪里处理异常?
答案 1:在代码层中实际上可以对错误做点什么
异常应该在实际上可以对错误做一些事情的代码层中处理。
“记录并重新抛出”模式通常被认为是一种反模式(正是由于您提到的原因,这会导致大量重复代码,并且不能真正帮助您做任何实际的事情。)
异常的意义在于它“不是预期的”。如果您正在工作的代码层在错误发生时无法做一些合理的事情来继续成功处理,那就让它冒泡吧。
如果您正在处理的代码层可以在错误发生时继续执行某些操作,那么这就是处理错误的地方。 (并且返回“失败”的 http 响应代码算作“继续处理”的一种方式。您正在避免程序崩溃。)
-source: softwareengineering.stackexchange
答案 2:集中处理错误,而不是在中间件内
如果没有一个专门的错误处理对象,由于处理不当,重要错误隐藏在雷达下的可能性就更大。错误处理程序对象负责使错误可见,例如通过写入格式良好的记录器,将事件发送到某些监控产品,如 Sentry、Rollbar 或 Raygun。大多数 Web 框架,如 Express,都提供了错误处理中间件机制。典型的错误处理流程可能是:某些模块抛出错误 -> API 路由器捕获错误 -> 将错误传播到负责捕获错误的中间件(例如 Express、KOA) -> 调用集中式错误处理程序 - > 中间件被告知此错误是否是不受信任的错误(不可操作),因此它可以正常重启应用程序。请注意,在 Express 中间件中处理错误是一种常见但错误的做法——这样做不会涵盖在非 Web 界面中引发的错误。
-source; Handle errors centrally, not within a middleware
所以这两个原则似乎不一致。 #1 说如果可以的话,马上处理。所以对我来说,它将在服务层中。但是#2说集中处理它,就像在服务器文件中一样。我选择了#2。
我的决定:在自定义错误类中抛出错误
它结合了人们建议的几种方法。我正在抛出错误,但我不是“记录并重新抛出”,正如上面的答案所警告的那样。相反,我将错误放入包含更多信息的自定义错误中并抛出。它被集中记录和处理。
首先在我的服务层中,这是抛出错误的方式:
async addUser(user) {
let newUser;
try {
newUser = await this.UserModel.create(user);
} catch (err) {
throw new ApplicationError( // custom error
{
user, // params that are useful
err, //original error
},
`Unable to create user: ${err.name}: ${err.message}` // error message
);
}
return newUser;
}
ApplicationError 是一个自定义错误类,它接受一个信息对象和一条消息。我从这里得到了这个想法:
在这种模式下,我们将使用ApplicationError 类启动我们的应用程序,这样我们就知道我们明确抛出的应用程序中的所有错误都将从它继承。所以我们将从以下错误类开始:
-source: smashingmagazine
您可以在您的自定义错误类中添加其他有用的信息,甚至可以使用什么 EJS 模板!因此,您可以真正创造性地处理错误,具体取决于您如何构建自定义错误类。我不知道这是否“正常”,也许包含 EJS 模板并不可靠,但我认为这是一个值得探索的有趣概念。您可以考虑其他更可靠的方式来动态响应错误。
目前这是handleError 文件,但我可能会将其更改为处理自定义错误以创建一个信息更丰富的页面。 :
const logger = require("./logger");
module.exports = (err, req, res, next) => {
if (res.headersSent) {
return next(err);
}
logger.log("Error:", err);
return res.status(500).render("500", {
title: "500",
});
};
然后我将该函数作为最后一个中间件添加到我的服务器文件中:
app.use(handleError);
总之,似乎在如何处理错误方面存在一些分歧,尽管似乎更多人认为您应该抛出错误并可能集中处理它。找到适合您的方法,保持一致并记录下来。