【问题标题】:Retry promise himself after fail in node js在节点js中失败后重试自己的承诺
【发布时间】:2018-02-17 10:59:27
【问题描述】:

我想在 Promise 中重试我的请求。如果我总是有一个 401 错误作为循环,我想启动我的刷新:(如果我在刷新时有 401 循环直到 200)

我试过这个:

const request = require('request');
let conf    = require('../conf');

let core_service = require('coreService');

let self = module.exports = {
    get_count_questions: function() {
        return new Promise((resolve, reject) => {
            request({
                method: 'GET',
                uri: 'http://api/count-questions',
                auth: {
                    'bearer': conf.token
                },
                json: true
            }, function (error, response, body) {
                if (!error && response.statusCode === 200) {
                    resolve(body);
                } else if (!error && response.statusCode === 401) {
                    core_service.refreshToken().then((data) => {
                        console.log('token refresh');
                        return self.get_count_questions();
                    })
                } else {
                    reject(error);
                }
            })
        });
    }
};

我只尝试了“self.get_count_questions();”没有回报,但它不起作用。我没有错误消息,只是我的应用程序冻结了。

我在我的 console.log 中看到“令牌刷新”,但在我的应用程序冻结之后...

编辑

我用这个修改过,感觉更好,但是刷新令牌很慢。就在 401 之前,我的应用停止,大约 1 分 40 秒后,运行:

else if (!error && response.statusCode === 401) {
    console.log('need refresh token');
    core_service.refreshToken()
                .then((response) => {
                    console.log(response);
                    resolve(self.get_count_questions())
                } );
}

我的 refreshToken 函数:

refreshToken: function () {
    return new Promise((resolve, reject) => {
        request({
            method: 'GET',
            uri   : 'http://api/refresh',
            auth  : {
                'bearer': conf.token
            },
            json  : true
        }, function (error, response, body) {
            console.log('=====> refresh token <======');
            conf.token = body.data;
            console.log('new Token');
            console.log('=====> end refresh token <======');
            if (!error && response.statusCode === 200) {
                resolve('Refresh token successful');
            } else {
                reject('Error refresh');
            }
        })
    });
}

如果我在每个请求上刷新我的令牌,我就会遇到问题:

if (!error && response.statusCode === 200) {
     core_service.refreshToken().then((data)=> {
         resolve(body);
     });

}

【问题讨论】:

    标签: javascript node.js promise es6-promise


    【解决方案1】:

    你必须解决返回的承诺。当你使用一个 Promise 解决时,你基本上是说,用这个 Promise 的结果来完成这个 Promise。

    var prom = function() {
      return new Promise((resolve, reject) => {
        console.log('request start')
        setTimeout(() => {
          console.log('request finish')
          let ran = Math.random();
    
          if (ran < 0.1)
            resolve('success');
    
          else if (ran >= 0.1 && ran < 0.98)
            setTimeout(() => {
              console.log('retry');
              resolve(prom());
            }, 500);
    
          else
            reject('error');
    
        }, 500);
      });
    };
    
    prom().then(console.log.bind(console), console.log.bind(console));

    所以你应该像这样更新你的 else if 块:

    else if (!error && response.statusCode === 401) {
      console.log('need refresh token');
      core_service.refreshToken()
        .then(() => resolve(self.get_count_questions()));
    } 
    

    【讨论】:

    • 感谢您的回答!我更新了我的代码和我的帖子,但我有一个错误“(节点:803)UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝ID:1):null(节点:803)DeprecationWarning:不推荐使用未处理的承诺拒绝。将来,承诺未处理的拒绝将使用非零退出代码终止 Node.js 进程。"
    • @JérémieChazelle 似乎您的 core_service.refreshToken 正在引发错误。您的第一次编辑对于处理来自此 refreshToken 方法的错误是有意义的。这不是重试承诺的问题。您的代码有效。
    • 谢谢!我修改了刷新功能!感觉好多了,但是刷新很慢。如果我在所有请求上直接使用刷新令牌,刷新速度非常快。但是如果我使用你的代码,刷新它的协商很慢,我用图片更新了我的代码。就在 401 之前,我的应用停止,大约 1 分 40 秒后,运行
    • @JérémieChazelle 我再次猜测,但您尝试访问的 api 可能有 90 秒的超时。因此,当您的令牌不正确时,api 不会立即失败,而是等待 90 秒失败。如果您拥有 api,则可以在 api 端更改此行为。如果不这样做,则必须在请求中指定合理的超时时间。查看请求的超时选项。
    • 确实我有问题如果我总是在 1 分钟后刷新我的令牌。嗯...我将 Laravel 与 JWT Token (tymondesigns/jwt-auth) 和我的 conf 一起使用:'ttl' => 1, 'refresh_ttl' => 20160, (ttl 1 用于测试刷新)
    【解决方案2】:

    您正在进行递归调用,但您实际上从未对它的承诺做任何事情。因此,您最初的承诺永远不会解决。

    您需要将递归调用(到refreshToken().then())的承诺传递给resolve()

    【讨论】:

    • @JérémieChazelle:不;您应该将整个承诺从then() 传递到resolve()resolve(...then(...))
    【解决方案3】:

    现在你几乎拥有它。

    但是:

    return core_service.refreshToken()
                       .then(self.get_count_questions);
    

    您将其返回给request() 回调;该返回值没有被使用。

    相反,您需要将原来的承诺从then() 解析为新的承诺,方法是将它传递给原来的resolve() 函数:

    resolve(core_service.refreshToken().then(...));
    

    【讨论】:

    • 感谢您的回答!我试过:resolve(core_service.refreshToken().then((data) => { resolve(self.get_count_questions); }));但我有一个错误
    • 您只能拨打resolve()一次。在 then() 中调用它会忽略嵌套承诺中的失败。
    【解决方案4】:

    我知道这不是最佳解决方案,但它可能会有所帮助

    const request = require('request');
        let conf    = require('../conf');
    
        let core_service = require('coreService');
    
        let self = module.exports = {
            get_count_questions: function() {
                return new Promise((resolve, reject) => {
                    request({
                        method: 'GET',
                        uri: 'http://api/count-questions',
                        auth: {
                            'bearer': conf.token
                        },
                        json: true
                    }, function (error, response, body) {
                 try{
                        if (!error && response.statusCode === 200) {
                            resolve(body);
                        } else if (!error && response.statusCode === 401) {
                           throw new Error(response.statusCode);
                        } else {
                            reject(error);
                        }
                     }catch(exc){if(exc === 401){
                                core_service.refreshToken().then((data) => {
                                console.log('token refresh');
                                return self.get_count_questions();
                            })      
                           }
    
                        }       
                    })
                });
            }
        };
    

    【讨论】:

      【解决方案5】:

      您需要在重试请求后调用初始解析/拒绝函数:

      let self = module.exports = {
          get_count_questions: function() {
              return new Promise((resolve, reject) => {
                  request({
                      method: 'GET',
                      uri: 'http://api/count-questions',
                      auth: {
                          'bearer': conf.token
                      },
                      json: true
                  }, function (error, response, body) {
                      if (!error && response.statusCode === 200) {
                          resolve(body);
                      } else if (!error && response.statusCode === 401) {
                          core_service.refreshToken().then((data) => {
                              console.log('token refresh');
                              self.get_count_questions().then((data) => {
                                // call initial resolve function
                                resolve(data);
                              }).catch((error) => {
                                // call initial reject function
                                reject(error);
                              });
                          }).catch((error) => {
                              // reject if refreshToken fails
                              reject(error);
                          });
                      } else {
                          reject(error);
                      }
                  })
              });
          }
      };
      

      您还必须确保第二次调用实际解决/拒绝并且不会进入另一个 401。因为否则您将有无限递归。

      【讨论】:

      • 我尝试使用您的代码,但刷新后,我的应用停止了,不要冻结而是停止
      • 你是否也为递归调用添加了catch?
      • 您还应该在core_service.refreshToken()reject 内部添加一个catch。
      • 感谢您的帮助,我尝试使用您的代码添加 refreshToken 函数
      • 我有同样的问题,我的应用停止了
      猜你喜欢
      • 1970-01-01
      • 2018-09-26
      • 1970-01-01
      • 2016-09-08
      • 2015-01-08
      • 1970-01-01
      • 2019-05-27
      • 2017-07-23
      • 1970-01-01
      相关资源
      最近更新 更多