【问题标题】:How to handle request-promise errors properly?如何正确处理请求承诺错误?
【发布时间】:2015-05-30 00:09:25
【问题描述】:

所以我在一个脚本中使用了request-promise,该脚本循环了一个url列表和请求触发。然后我想在所有请求完成后对收到的数据做一些事情。

我有以下几点:

var rp = require('request-promise');

rp.get({
    uri: 'http://httpstat.us/500',
    transform: function(body, res){
        res.data = JSON.parse(body);
        return res;
    }
}).then(function(res){
    results.push(res.data);
})
.catch(function(err){
    should.throw.error.to.console();
    var respErr  = JSON.parse(err.error);
    var errorResult = {
        origUrl: respErr.origUrl,
        error: respErr
    };
    results.push(errorResult);
});

如您所见.. http://httpstat.us/500 抛出 500,这会导致运行 .catch() 块。我在强迫一个错误。 should.throw.error.to.console(); 应该向控制台抛出一个错误,但脚本只是静默退出,没有任何错误代码 (Process finished with exit code 0)。

我假设 request-promise 正在从节点的 http 捕获错误,当页面没有返回 2xx 代码时,然后将其传递回 catch() 回调。但是任何后续错误最终都会默默地失败。我到底该如何处理这个问题,以便我的其余代码仍能正确抛出错误?

相关GitHubissue

【问题讨论】:

  • 是什么让你认为这里的任何东西都会向控制台抛出错误?
  • 在我的实际代码中(不是上面的示例),我有一个Q.all(),一旦我的所有请求完成就会触发.. 在那,我打电话给一个发送所有结果的电子邮件在一封电子邮件中。由于滥用.catch(),我在随后的代码中有一个致命的JS错误导致脚本静默失败。请参阅下面接受的答案和相关的 GitHub 对话,了解为什么会这样。

标签: javascript node.js promise


【解决方案1】:

您所说的“任何后续错误最终都会以静默方式失败”是什么意思?如果最初的 Promise rp 失败,catch 会在失败时执行……在失败的时候。 一旦 Promise 被拒绝,就是这样,不会有“后续错误”。

另外,should 看起来像一个断言(例如来自chai),这表明您正在尝试对此进行测试。 Chai 的should.throw 不会抛出错误,它会检查是否抛出了错误。如果您正在对此进行测试,您需要向测试(it 块)表明测试是异步的,而不是同步的 - 通常通过命名和调用 done 参数。否则,请求将被发送出去,然后在做出任何响应之前,脚本将同步结束并且不会监听任何错误。

更重要的是,您正在指定某些东西应该throw 到控制台,但您的代码中没有任何东西throws!如果您确实写入了throw,您应该了解throwthencatch 中只会导致来自该处理程序的传出承诺被抛出的值拒绝(是的,catch 导出一个新的promise,就像then——它是.then(null, errHandler)的100%糖。如果你想把错误重新扔回窗口,你需要用Bluebird的.done()promise方法完成链,在请求中访问- 通过有点神秘的.promise().done() 承诺。但即使在这种情况下,您仍然需要指定您正在进行异步测试。

简而言之,您认为其中的某些代码应该做什么以及它与您的预期有何不同并不完全清楚。请澄清!

var rp = require('request-promise');

rp.get({ // start an async call and return a promise
    uri: 'http://httpstat.us/500',
    transform: function(body, res){
        res.data = JSON.parse(body);
        return res;
    }
}).then(function(res){ // if rp.get resolves, push res.data
    results.push(res.data);
})
.catch(function(err){ // if rp.get rejects (e.g. 500), do this:
    should.throw.error.to.console(); // test if something is thrown (but nothing has been!)
    var respErr  = JSON.parse(err.error);
    var errorResult = {
        origUrl: respErr.origUrl,
        error: respErr
    };
    results.push(errorResult); // push an object with some of the error info into results
});

// this line (e.g., end of script) is reached before any of the async stuff above settles. If you are testing something, you need to make the test async and specify when it's complete by invoking `done()` (not the same as ending the promise chain in Bluebird's `.done()`).

【讨论】:

  • 对应该的引用不是“测试”代码。我在问题中没有提到测试。那条线完全按照它所说的“应该”做,并抛出一个致命的“未定义引用”错误。正如问题所指出的那样,一个错误最终不会出现在 stdout 或 stderr 中......如果我在 catch 之外添加后续逻辑,任何其他致命错误也会静默失败。
  • @RavenHursT——好的,我想我终于明白了——你正试图抛出一个错误。为什么你不简单地throw new Error() 我猜不出来,但是现在已经澄清了,我的答案的其余部分适用:catch 中抛出的错误永远不会击中窗口。它拒绝catch 返回的承诺。如果您希望将错误重新抛出到窗口,则必须使用 request-promise 和 Bluebird 文档中指定的 .promise().done()
【解决方案2】:

显然,promise 中的 .catch() 基本上是 JS try-catch 的包装器。因此,为了在编写完一个处理程序后将后续错误记录到控制台,您必须有第二个处理程序将最终错误抛出到控制台。

在 GitHub 上的更多信息:https://github.com/request/request-promise/issues/48#issuecomment-107734372

【讨论】:

    猜你喜欢
    • 2020-02-19
    • 2015-04-03
    • 1970-01-01
    • 2020-04-11
    • 2019-08-21
    • 1970-01-01
    • 2015-07-29
    • 1970-01-01
    • 2018-09-21
    相关资源
    最近更新 更多