1

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

例如,我想有函数 ,,,sendGetsendPost。在理想情况下,这些函数将实现核心函数,只是使用不同的参数。sendJSONsendFilemakeRequest

我希望每个包装器都返回一个 promise,因此调用者可以对结果做任何事情。

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

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


// intended usage of wrapper
sendGet('http://example.com', 3).then().catch()

// wrapper applies makeRequest fnc with various arguments 
const sendGet = (url, retries) => {
    return makeRequest('GET', url, retries)
}

const sendPost = (url, retries) => {
    return makeRequest('POST', url, retries)
}

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

        const options = {/*method, hostname, etc */};

        const request = http.request(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)
            })
        })

        request.end();
    })
}

4

2 回答 2

1

试试这个,原来的函数现在叫做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
于 2021-05-24T15:08:02.807 回答
0

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

现场演示

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()
于 2021-05-24T16:00:08.277 回答