重试 nodejs http.request (post,put,delete)

乔纳森·恩斯林

请在不使用 nodejs 中的任何第三方模块的情况下实现错误/条件重试的正确方法是什么?

我不确定如何在错误上调用相同的函数,以及如何将原始回调/数据传递给新调用的函数?

我需要销毁/结束套接字吗?

我尝试寻找示例,但只找到了对第三方模块和 http.get 示例的引用,这些示例似乎不起作用。一个人如何测试这个?我尝试了以下但没有成功:

      async pingApi(cb) {
        let options = {
        "method":"post",
         "path": `/API/pingAPI?${this.auth}`, /ect do I reference this path?
          }
        };
        let request = await http.request(options, (response) => {
          let body = new Buffer(0);
          response.on('data', (chunk) => {
            body = Buffer.concat([body, chunk]);
          });
          response.on('end', function () {
            if (this.complete) {
              let decoded = new Buffer(body, 'base64').toString('utf8')
              let json = JSON.parse(decoded);
              if (json.result != 'OK') {
                setTimeout(pingApi, 1000); //cant pass callback
              } else {
                cb(null, json.result) //works
              }
            }
          });
        })
        request.end(); //does the socket need to be closed if retry is this function?
      }

任何帮助,指出正确的方向或批评将不胜感激,因为我认为这对我来说是一个非常重要的学习曲线。

先感谢您,

jfriend00

我不确定如何在错误上调用相同的函数,以及如何将原始回调/数据传递给新调用的函数?

我不确定您函数中的其他所有内容是否正确,但是您可以通过更改以下内容来修复您所询问的递归:

setTimeout(pingApi, 1000); //cant pass callback

对此:

setTimeout(() => {
    this.pingApi(cb);
}, 1000);

您没有在此处显示整个上下文,但如果pingApi()是一个方法,那么您还需要跟踪this可以调用this.pingApi(db)您可以this使用如下箭头函数回调来保留 的值

response.on('end', () => { ... });

我注意到的其他事情在这里看:

  1. 没有理由使用await http.request(). http.request()不返回承诺,因此使用await它不会做任何有用的事情。
  2. 没有await,就没有理由声明您的函数,async因为没有人使用它返回的承诺。
  3. 目前尚不清楚要做什么if (this.complete)由于这是在常规函数回调中,因此 的值this不会是您的 pingApi 对象。您应该this在通常的范围内保存更高的范围,const self = this或者内部的所有回调都需要是箭头函数,以便this保留的值
  4. 您可能应该放弃try/catchJSON.parse()因为如果输入不是完美的 JSON,它可能会抛出。
  5. 您可能不应该永远重试。服务器真的很讨厌永远重试的客户端,因为如果出现问题,客户端可能会无限期地每秒攻击服务器。我建议一定数量的最大重试,然后放弃一个错误。

我需要销毁/结束套接字吗?

不,这将在请求结束后自动发生。

一个人如何测试这个?

你必须在你的服务器中创建一个测试路由,它返回前几个请求的错误条件,然后返回一个成功的响应,看看你的代码是否可以使用它。


这是对代码修复的尝试(未经测试):

const maxRetries = 10;

pingApi(cb, cnt = 0) {
    let options = {
    "method":"post",
     "path": `/API/pingAPI?${this.auth}`, // ect do I reference this path?
    };
    let request = http.request(options, (response) => {
      let body = new Buffer(0);
      response.on('data', (chunk) => {
        body = Buffer.concat([body, chunk]);
      });
      response.on('end', () => {
        if (this.complete) {
          let decoded = new Buffer(body, 'base64').toString('utf8')
          try {
            let json = JSON.parse(decoded);
            if (json.result != 'OK') {
                if (cnt < maxRetries)
                    setTimeout(() => {
                        this.pingApi(cb, ++cnt);
                    }, 1000);
                 } else {
                    cb(new Error("Exceeded maxRetries with error on pingApi()"));
                 }
            } else {
                cb(null, json.result) //works
            }
          } catch(e) {
              // illegal JSON encountered
              cb(e);
          }
        }
      });
    })
    request.end();
 }

关于此代码的尚待解决的问题:

  1. 什么在this.complete做什么this,它应该参考什么?
  2. 为什么没有request.write()发送 POST 请求的正文?

我知道你不需要外部模块,但我更喜欢的方法是使用 promises 并使用 request-promise 包装器,http.request()因为它为你处理了很多代码(为你检查 response.status,解析 JSON对你来说,使用承诺接口等......)。你可以看到代码干净了多少:

const rp = require('request-promise');
const maxRetries = 5;

pingApi(cnt = 0) {
    let options = {
        method: "post",
        url: `http://somedomain.com/API/pingAPI?${this.auth}`, 
        json: true
    };
    return rp(options).then(result => {
        if (result.result === "OK") {
            return result;
        } else {
            throw "try again";  // advance to .catch handler
        }
    }).catch(err => {
        if (cnt < maxRetries) {
            return pingApi(++cnt);
        } else {
            throw new Error("pingApi failed after maxRetries")
        }
    });
}

然后,示例用法:

pingApi().then(result => {
    console.log(result);
}).catch(err => {
    console.log(err);
})

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章