我的用例是发送自定义 JSON 错误消息,因为我使用 express 来支持我的 REST API。我认为这是一个相当普遍的情况,因此在我的回答中将重点关注这一点。
简洁版本:
快速错误处理
像其他中间件一样定义错误处理中间件,除了使用四个参数而不是三个参数,特别是使用签名(err、req、res、next)。...在其他 app.use() 和路由调用之后,您最后定义错误处理中间件
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
});
通过执行以下操作从代码中的任何位置引发错误:
var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
长版
抛出错误的规范方法是:
var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)
默认情况下,Express 通过将其巧妙地打包为带有代码 404 的 HTTP 响应和由附加堆栈跟踪的消息字符串组成的正文来处理此问题。
例如,当我使用 Express 作为 REST 服务器时,这对我不起作用。我希望将错误作为 JSON 发送回,而不是 HTML。我也绝对不希望我的堆栈跟踪移到我的客户身上。
我可以使用例如发送 JSON 作为响应req.json()
。类似的东西req.json({ status: 404, message: 'Uh oh! Can't find something'})
。或者,我可以使用req.status()
. 将两者结合起来:
req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});
这就像一个魅力。也就是说,我发现每次出现错误时都很难输入,而且代码不再像我们的那样自我记录next(err)
。它看起来与发送正常(即有效)响应 JSON 的方式太相似了。此外,规范方法引发的任何错误仍会导致 HTML 输出。
这就是 Express 的错误处理中间件的用武之地。作为我的路线的一部分,我定义:
app.use(function(err, req, res, next) {
console.log('Someone tried to throw an error response');
});
我还将 Error 子类化为自定义 JSONError 类:
JSONError = function (status, message) {
Error.prototype.constructor.call(this, status + ': ' + message);
this.status = status;
this.message = message;
};
JSONError.prototype = Object.create(Error);
JSONError.prototype.constructor = JSONError;
现在,当我想在代码中抛出错误时,我会:
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
回到自定义错误处理中间件,我将其修改为:
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
}
将 Error 子类化为 JSONError 很重要,因为我怀疑 Express 会instanceof Error
检查传递给 a 的第一个参数,next()
以确定是否必须调用正常处理程序或错误处理程序。我可以删除instanceof JSONError
检查并进行少量修改以确保意外错误(例如崩溃)也返回 JSON 响应。