簡體   English   中英

重試Node.js http.request(發布,發布,刪除)

[英]Retry 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?
      }

指出正確方向或提出批評的任何幫助將不勝感激,因為我認為這對我來說是非常重要的學習曲線。

先感謝您,

我不確定如何針對錯誤調用相同的函數,以及如何將原始回調/數據傳遞給新調用的函數?

我不確定函數中的其他所有內容是否正確,但是您可以通過更改以下內容來解決所要求的遞歸:

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因為沒有人使用它返回的promise。
  3. 目前尚不清楚if (this.complete)應該做什么。 由於這是一個常規的回調函數里面,價值this不會是你pingApi對象。 您應該保存this在一般范圍內具有較高的const self = this或全部回調內部需要是箭頭功能,因此值this被保留。
  4. 您可能應該將try/catch放在JSON.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請求的正文?

我知道您不要求任何外部模塊,但是我這樣做的首選方法是使用http.request()http.request()周圍使用請求-承諾包裝器,因為它為您處理了很多此類代碼(檢查response.status為您服務,為您解析JSON,使用promise接口等)。 您可以看到代碼有多干凈:

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);
})

您對核心節點服務器使用async / await引起了我的興趣,我已嘗試盡可能多地使用這種新的異步功能。

這就是我最終得到的結果: https : //runkit.com/marzelin/pified-ping

 const pify = require("util").promisify; const http = require("http"); const hostname = "jsonplaceholder.typicode.com"; const failEndpoint = "/todos/2"; const goodEndpoint = "/todos/4"; let options = { method: "get", path: `${failEndpoint}`, hostname }; async function ping(tries = 0) { return new Promise((res) => { const req = http.request(options, async (response) => { let body = new Buffer(0); response.on("data", (chunk) => { body = Buffer.concat([body, chunk]); }) const on = pify(response.on.bind(response)); await on("end"); let decoded = new Buffer(body, 'base64').toString('utf8') let json = JSON.parse(decoded); if (json.completed) { return res("all good"); } if (tries < 3) { console.log(`retrying ${tries + 1} time`); return res(ping(tries + 1)); } return res("failed"); }) req.on('error', (e) => { console.error(`problem with request: ${e.message}`); }); // write data to request body req.end(); }) } const status = await ping(); "status: " + status 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM