Son*_*123 27 rest error-handling mongoose
我是一个绝对的NodeJS初学者,想要用Express和Mongoose创建一个简单的REST-Web服务.
什么是在一个中心位置处理猫鼬错误的最佳做法?
当发生数据库错误的任何地方时,我想返回一个带有错误消息的Http-500-Error-Page:
if(error) {
res.writeHead(500, {'Content-Type': 'application/json'});
res.write('{error: "' + error + '"}');
res.end();
}
Run Code Online (Sandbox Code Playgroud)
在旧教程http://blog-next-stage.learnboost.com/mongoose/中我读到了一个全局错误监听器:
Mongoose.addListener('error',function(errObj,scope_of_error));
Run Code Online (Sandbox Code Playgroud)
但这似乎不起作用,我在Mongoose官方文档中找不到关于这个监听器的东西.我是否在每次Mongo请求后检查错误?
aar*_*ann 43
如果您使用的是Express,通常会直接在路由中或在mongoose之上构建的api中处理错误,并将错误转发给next.
app.get('/tickets', function (req, res, next) {
PlaneTickets.find({}, function (err, tickets) {
if (err) return next(err);
// or if no tickets are found maybe
if (0 === tickets.length) return next(new NotFoundError));
...
})
})
Run Code Online (Sandbox Code Playgroud)
该NotFoundError会在你嗤之以鼻的错误处理中间件提供量身定制的消息.
有些抽象是可能的,但您仍然需要访问该next方法才能将错误传递到路径链中.
PlaneTickets.search(term, next, function (tickets) {
// i don't like this b/c it hides whats going on and changes the (err, result) callback convention of node
})
Run Code Online (Sandbox Code Playgroud)
至于集中处理猫鼬错误,并不是真正处理所有错误的地方.错误可以在几个不同的级别处理:
connectionconnection你的模型正在使用的错误发出,所以
mongoose.connect(..);
mongoose.connection.on('error', handler);
// or if using separate connections
var conn = mongoose.createConnection(..);
conn.on('error', handler);
Run Code Online (Sandbox Code Playgroud)
对于典型的查询/更新/删除,错误将传递给您的回调.
PlaneTickets.find({..}, function (err, tickets) {
if (err) ...
Run Code Online (Sandbox Code Playgroud)
如果您没有传递回调,那么如果您正在侦听它,则会在模型上发出错误:
PlaneTickets.on('error', handler); // note the loss of access to the `next` method from the request!
ticket.save(); // no callback passed
Run Code Online (Sandbox Code Playgroud)
如果您没有传递回调并且没有在model级别上侦听错误,那么它们将在模型上发出connection.
这里的关键要点是,您希望以next某种方式访问以传递错误.
IMO 更简单、更最新的解决方案:
实例化数据库时处理连接级别错误:
const mongooseConnection = mongoose.createConnection(databaseURL)
mongooseConnection.on('error', err => {
throw new Error('Mongo database connexion error')
})
Run Code Online (Sandbox Code Playgroud)
如果您编写错误类型的字段或不正确地使用查询选项(填充、排序...),则可能会出现查询级别错误。try catch await我们可以使用比旧语法更具可读性/最新的语法promise.callback.catch(mongoose doc)
try {
await Band.findOne({ _id: badId }).exec();
} catch (err) {
throw new Error('Mongo database connexion error')
}
Run Code Online (Sandbox Code Playgroud)
=> 在您的所有应用程序中使用错误处理程序
上面 2 个示例中的错误处理不是很相关,因为您丢失了所有上下文信息(mongo 错误消息、堆栈跟踪、数据库名称、userId...)
您可以以集中的方式处理错误,以便可以将上下文信息与错误消息一起传递,如下所示:
try { ... } catch (err) {
throw ApplicationError(
'myMessage',
{
// Here we pass additional informations
// this will help handling the error on the express api side
httpCode: err instanceof mongoose.Error.ValidationError ? 422 : 500,
// with this one you can display original error messsage/stack trace
originalError: err,
// other contextual informations may be useful to display
// but be carreful not to display sensitive informations
// here (Eg DB connection string)
databaseName,
userId,
userRole,
methodName,
}
)
}
class ApplicationError extends Error {
constructor(errMsg, additionalInfos) {
// Here handle error as you want
}
}
Run Code Online (Sandbox Code Playgroud)
=> 使用请求处理程序以相同的方式处理所有猫鼬查询
避免重复代码的常见模式是创建一个函数来为您处理 mongoose Promise 的执行:
async function afterRequest(mongoosePromise, { sort, page, limit }) {
try {
if (sort) promise.sort(sort)
// PAGINATION
if (page) promise.skip(localConfig.page * limit || 25).limit(limit || 25)
else if (limit) promise.limit(limit)
return await promise.exec()
} catch (err) { /** handle error like in the above code */ }
}
Run Code Online (Sandbox Code Playgroud)
所以我们现在可以这样使用它:
const mongoosePromise = Band.find()
afterRequest(mongoosePromise, { page: 1, limit: 10 })
Run Code Online (Sandbox Code Playgroud)
这种模式的优点是:
上面只是一个非常简单的示例,但更进一步,我们可以实现以下一些功能:
{ companyId: user.companyId }| 归档时间: |
|
| 查看次数: |
23274 次 |
| 最近记录: |