如何在 Node.js 中使用承诺和重试发出 HTTP 请求

问题描述

我正在尝试围绕 Node HTTP/S module requests 编写一些包装器,而不使用 axios。 node-fetch 或任何其他 3rd 方模块。

例如,我想要函数 sendGetsendPostsendJSONsendFile 等。在理想情况下,这些函数将实现核心功能{{1 }},只是参数不同。

我希望每个包装器都返回一个承诺,这样调用者就可以对结果做任何事情。

我还希望包装器有一个参数,在失败的情况下请求重试次数

所以想法是这样的。到目前为止,我能够制作一个包装器并通过承诺。但我无法添加重试失败的能力。它应该(在理想情况下)是 makeRequest 函数的一部分,但是当与 promise 结合时我无法这样做。谢谢你的想法

makeRequest

解决方法

试试这个,原来的函数现在叫做 tryRequest,外面有 for 循环来做重试

// core function
const makeRequest = async (method,url,retries = 0) => {
    const tryRequest = async () => {
        // returns reject on bad status
        // returns resolve with body on successful request
        return new Promise((resolve,reject) => {

            const options = {method,};

            const request = http.request(url,options,(response) => {
                let chunks = [];

                if (response.statusCode < 200 || response.statusCode >= 300) {
                    return reject('bad status code')
                }

                // collect data
                response.on('data',(chunk => {
                    chunks.push(chunk)
                }))

                // resolve on end of request
                response.on('end',() => {
                    let body = Buffer.concat(chunks).toString();
                    return resolve(body)
                })
            })

            // reject on error of request (Service down)
            request.on('error',function (error) {
                reject(error);
            })

            request.end();
        })
    }

    for (let i=1; i<=retries; i++) {
        try {
            console.log('Try No.',i);
            url = url.substring(0,url.length - 1); // TODO To test,delete after it
            return await tryRequest();
        } catch(error) {
            if (i < retries) continue;
            throw error;
        }
    }
}

测试

await sendGet('http://example.com/abc',3); // Will work at the 3th try retry
await sendGet('http://example.xyz/abc',3); // Will fail server not found
,

您可以使用自定义承诺和 axios 或任何其他基于承诺的请求:

(Live Demo)

import { CPromise } from "c-promise2";
import cpAxios from "cp-axios";

const url =
  "https://run.mocky.io/v3/7b038025-fc5f-4564-90eb-4373f0721822?mocky-delay=2s";

(async()=>{
  const response= await CPromise.retry(() => cpAxios(url).timeout(5000));
})();

更复杂:

import { CPromise } from "c-promise2";
import cpAxios from "cp-axios";

const url =
  "https://run.mocky.io/v3/7b038025-fc5f-4564-90eb-4373f0721822?mocky-delay=2s";

const promise = CPromise.retry(
  (attempt) => {
    console.log(`Attempt [${attempt}]`);
    return cpAxios(url).timeout(attempt * 1000 + 500);
  },{ retries: 3,delay: (attempt) => attempt * 1000 }
).then(
  (response) => console.log(`Response: ${JSON.stringify(response.data)}`),(err) => console.warn(`Fail: ${err}`)
);

// promise.pause()
// promise.resume()
// promise.cancel()