【问题标题】:How to throw an error from an async mongoose middleware post hook如何从异步 mongoose 中间件 post hook 中抛出错误
【发布时间】:2018-12-27 16:42:15
【问题描述】:

从异步Mongoose middleware post hook 抛出错误的正确方法是什么?

代码示例

以下 TypeScript 代码使用 mongoose 的 post init 事件来运行一些检查,这些检查在函数从 mongoDb 检索文档时触发。此示例中的 postInit() 函数正在执行一些背景检查。它应该在某些情况下失败,然后返回Promise.reject('Error!');

schema.post('init', function (this: Query<any>, doc: any) {
    return instance.postInit(this, doc) 
    .catch( err => {
        return err;
    });
});

钩子工作正常。 IE。以下代码触发了钩子:

MyMongooseModel.findOne({ _id : doc.id}, (err, o : any) => {
    console.log(o);
});

但是,如果postInit() 失败,则不会将错误传递回调用函数。而是返回文档。

预期行为

我正在寻找将此错误传递给调用函数的正确方法。如果背景检查失败,则调用函数不应取回文档。

我尝试了不同的方法来引发此错误。例如。 throw new Error('Error');。但是,这会导致 UnhandledPromiseRejectionWarning 并仍然返回文档。

【问题讨论】:

    标签: javascript node.js mongodb typescript mongoose


    【解决方案1】:

    这里是 Mongoose 的维护者。不幸的是,init() 钩子是同步的,我们还没有很好地记录它。我们打开了GitHub issue 并将尽快添加文档。在post('init') 中报告错误的唯一方法是throw

    const assert = require('assert');
    const mongoose = require('mongoose');
    mongoose.set('debug', true);
    
    const GITHUB_ISSUE = `init`;
    const connectionString = `mongodb://localhost:27017/${ GITHUB_ISSUE }`;
    const { Schema } = mongoose;
    
    run().then(() => console.log('done')).catch(error => console.error(error.stack));
    
    async function run() {
      await mongoose.connect(connectionString);
      await mongoose.connection.dropDatabase();
    
      const schema = new mongoose.Schema({
        name: String
      });
      schema.post('init', () => { throw new Error('Oops!'); });
    
      const M = mongoose.model('Test', schema);
    
      await M.create({ name: 'foo' });
    
      await M.findOne(); // Throws "Oops!"
    }
    

    这是因为 Mongoose 假定 init() is synchronous internally

    【讨论】:

      【解决方案2】:

      在这个 post init hook 方法中,您只会收到一个 doc

      Document.prototype.init()

      Parameters doc «Object» 返回的文档 mongo 在没有设置器或标记任何内容的情况下初始化文档 修改。

      从 mongodb 返回文档后在内部调用。

      Mongoose 文档:Init HookDocumentation

      而要触发错误,您需要一个 done 或 next 方法:

      发布中间件

      post 中间件在被钩子方法和它的所有内容之后执行 预中间件已经完成。发布中间件不直接接收 流量控制,例如没有 next 或 done 回调传递给它。邮政 钩子是一种为这些注册传统事件侦听器的方法 方法。

      Mongoose 文档:Post Middleware

      如果您只想知道通话中是否发生错误,请更改为:

      MyMongooseModel.findOne({ _id : doc.id}, (err, o : any) => {
            if(err) {
              throw new Error(err);
            }
      
            console.log(o);
          });
      

      如果您想传播错误,一种选择是使用 pre 钩子方法:

      schema.pre('save', function(next) {
        const err = new Error('something went wrong');
        // If you call `next()` with an argument, that argument is assumed to be
        // an error.
        next(err);
      });
      
      schema.pre('save', function() {
        // You can also return a promise that rejects
        return new Promise((resolve, reject) => {
          reject(new Error('something went wrong'));
        });
      });
      
      schema.pre('save', function() {
        // You can also throw a synchronous error
        throw new Error('something went wrong');
      });
      
      schema.pre('save', async function() {
        await Promise.resolve();
        // You can also throw an error in an `async` function
        throw new Error('something went wrong');
      });
      

      错误处理示例:Error Handling

      【讨论】:

        猜你喜欢
        • 2021-06-28
        • 1970-01-01
        • 2020-04-22
        • 2017-08-13
        • 1970-01-01
        • 2019-08-05
        • 2020-12-27
        • 2018-07-12
        • 2015-04-15
        相关资源
        最近更新 更多