如何在生产中处理 Express 中的 http 错误?



我正在开发快速应用程序,在我指定所有路由和中间件后,我在服务器末端有这个.js:

// Log errors
app.use(function (err, req, res, next) {
logger.error(err.stack);
if(process.env.NODE_ENV === 'production')
return res.status(500).send('Something broke!');
next(err);
});
// Start server
app.listen(port, () => {
logger.info('Server is up on port ' + port);
});

这样做的目的是捕获生产中的所有错误,并避免将敏感数据泄露给客户端。

我的一个控制器中有以下代码:

const createHTTPError = require('http-errors')
async function(req, res, next) {
try {
invoice = await Invoice.create({
// data
});
}catch (e) {
if(e instanceof Sequelize.ValidationError){
logger.error(e);
return next(createHTTPError(400, 'Validation did not pass: ' + e.message));
}
}
}

问题是,当next()http-errors对象调用时,它会冒泡到我的 catch-all 错误处理程序,但信息丢失,并且在其中 err 对象是具有以下参数的简单Error实例:

message = "Validation did not pass: notNull Violation: invoice.clientEmail cannot be null"
name = "BadRequestError"
stack = "BadRequestError: Validation did not pass: notNull Violation: invoice.clientEmail cannot be nulln    at module.exports (/home/XXXX/create-new-invoice.js:109:33)"

错误代码丢失。错误对象类型丢失(嗯,在名称中转换为字符串)。

我该怎么办?如果我删除我的 catchall,我冒着一些敏感信息被泄露的风险。谢谢

所以我最终得到了这段代码:

const HTTPErrors = require('http-errors');
const HTTPStatuses = require('statuses');
// ... set up express, middlewares, routes...
// Log errors
app.use(function (err, req, res, next) {
let messageToSend;
if(err instanceof HTTPErrors.HttpError){
// handle http err
messageToSend = {message: err.message};
if(process.env.NODE_ENV === 'development')
messageToSend.stack = err.stack;
messageToSend.status = err.statusCode;
}else{
// log other than HTTP errors (these are created by me manually, so I can log them when thrown)
logger.error(err.stack);
}
if(process.env.NODE_ENV === 'production' && !messageToSend){
messageToSend = {message: 'Something broke', status: 500};
}
if(messageToSend) {
let statusCode = parseInt(messageToSend.status,10);
let statusName = HTTPStatuses[statusCode];
res.status(statusCode);
// respond with html page
if (req.accepts('html')) {
res.send('<html><head><title>'+statusCode+' '+statusName+'</title></head><body><h1>'+statusCode+' '+statusName+'</h1>'+messageToSend.message+'<br/><br/>'+(messageToSend.stack ? messageToSend.stack : '')+'</body></html>');
return;
}
// respond with json
if (req.accepts('json')) {
let responseObject = { error: statusName, code: statusCode, message: messageToSend.message };
if(messageToSend.stack)
responseObject.stack = messageToSend.stack;
res.send(responseObject);
return;
}
// default to plain-text. send()
res.type('txt').send(statusName+' '+messageToSend.message);
return;
}
// if this is not HTTP error and we are not in production, let express handle it the default way
next(err);
});

此解决方案:

  • 检测并显示来自http-errors模块的 HTTP 错误(带有用于开发的堆栈跟踪,没有用于生产)
  • 对于任何其他错误,这取决于是在生产中(然后抛出通用 500 服务器错误)还是在开发中(让 Express 默认处理错误,这意味着使用堆栈跟踪将其打印出来)
  • 根据接受标头设置错误输出的格式(因此,如果应用需要 JSON,它会发送 JSON)

我还利用了 404 catchall 中的这个新的 catchall 函数:

// DEFAULT CATCH
app.use(function(req, res, next){
next(HTTPErrors(404));
});

最新更新