【发布时间】:2021-06-16 10:16:50
【问题描述】:
我需要在 node.js 上处理我的 API 服务器中的错误。 我创建了一个错误处理模块,它将错误(仅在开发模式下)以类似于以下的 JSON 对象发送到 API 客户端:
{
"status": "fail",
"error": {
"statusCode": 404,
"status": "fail",
"isOperational": true
},
"message": "no valid register found. Please provide a valid register",
"stack": "Error: no valid register found. Please provide a valid register\n at /Users/myUser/ITstuff/smarthome-heating/controllers/modbusController.js:77:21\n at async /Users/myUser/ITstuff/smarthome-heating/controllers/modbusController.js:73:17"
}
现在我遇到的问题是,当 switch 语句中没有 case 为真时,我需要在我的 API 控制器的子模块中创建一个新错误。
// this is the modbusHandler.setValue(doc, val, next) function
// 2) RUN PROGRAMMS
let checkVal;
switch (doc.register) {
case 0:
await client.writeCoil(doc.address + offset, !!val);
checkVal = await client.readCoils(doc.address + offset, 1);
break;
case 4:
await client.writeRegister(doc.address + offset, val);
checkVal = await client.readHoldingRegisters(doc.address + offset, 1);
break;
default:
throw new Error(
'no valid register found. Please provide a valid register'
);
}
这个时候,我是这样处理的:
// the function is wrapped in a try-catch statement
const val = await modbusHandler.setValue(doc, req.body.value, next).catch((err) => {
console.log('here it is');
return next(new AppError(err.message, 404));
});
res.status(200).json({
status: 'success',
data: {
val,
},
});
- 在 API 控制器中,调用带有 switch 语句的函数
- 如果没有大小写与表达式匹配,则会引发新的错误
- 捕获错误然后调用自定义错误并以 JSON 格式向客户端响应错误
这个解决方案并不真正有效,我收到响应错误,因为 API 控制器的功能没有返回。这会导致第二次响应,这当然不好。
我现在的问题是:我怎样才能以正确的方式解决这个问题?
自定义错误构造函数:
class AppError extends Error {
constructor(message, statusCode) {
// this is the official error message rom the error it self, this message will be in the response.json for the client
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
module.exports = AppError;
自定义错误处理程序:
module.exports = (err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
if (process.env.NODE_ENV === 'development') {
sendErrDev(err, res);
} else if (process.env.NODE_ENV === 'production') {
sendErrProd(err, res);
}
};
const sendErrDev = (err, res) => {
res.status(err.statusCode).json({
status: err.status,
error: err,
message: err.message,
stack: err.stack,
});
};
【问题讨论】:
-
如果您提供更多有关自定义错误处理程序的上下文,您可能能够更快地获得帮助。正如所写,看起来您的错误处理程序被用作中间件,这意味着当它实际到达 api 路由处理程序时,您的自定义错误处理程序已经发生了。也许显示你实际上在哪里
catching 错误 -
在 API 控制器中的函数调用之后,我使用
.catch从switch语句中捕获了错误。在这个.catch中,我返回一个新的自定义错误,它为客户端提供了一个 API 响应 -
是的,我的错误处理程序被用作中间件
app.use(AppError);也许我需要提一下,整个 API 控制器函数被包装在一个 try-catch 块中,其中 catch 简单地调用next。 -
因此,如果您使用的是 express 的内置路由功能,我认为是这种情况,问题是您的错误处理中间件在代码到达您的 API 之前就已运行控制器,所以当控制器抛出错误时,它永远不会回到中间件,如果这有意义的话。
-
据我了解,它是这样的:在
modbusHandler.setValue()中,switch语句恰好是默认值,这会引发错误。这个错误在函数被调用的地方被捕获并执行return next(new AppError(...,这是一个全局错误处理程序,它将以 JSON 格式为客户端提供响应。问题是代码在函数调用之后向前运行并到达响应的位置,这会导致第二个错误,因为 AppError 已经发送了响应。这正是我试图解决的第二个错误。
标签: javascript node.js rest express