获取重试请求(失败时)

dsa*_*ket 7 javascript polyfills fetch-api

我正在使用浏览器的本机提取API来处理网络请求.此外,我正在使用whatwg-fetch polyfill用于不支持的浏览器.

但是,如果请求失败,我需要重试.现在我找到了这个npm包whatwg-fetch-retry,但他们没有解释如何在他们的文档中使用它.有人可以帮我这个或建议我另类吗?

Jon*_*lms 10

人们可以轻松地包裹fetch(...)在循环和catch潜在错误中(获取仅拒绝网络错误等的返回承诺):

const RETRY_COUNT = 5;

async function fetchRetry(...args) {
  let count = RETRY_COUNT;
  while(count > 0) {
    try {
      return await fetch(...args);
    } catch(error) {
      // logging ?
    }

    // logging / waiting?

    count -= 1;
  }

  throw new Error(`Too many retries`);
}  
Run Code Online (Sandbox Code Playgroud)


Art*_*dez 7

我不喜欢递归,除非确实有必要。管理数量呈爆炸式增长的依赖关系也是一个问题。这是打字稿中的另一种选择。这很容易翻译成 JavaScript。

interface retryPromiseOptions<T>  {
    retryCatchIf?:(response:T) => boolean, 
    retryIf?:(response:T) => boolean, 
    retries?:number
}

function retryPromise<T>(promise:() => Promise<T>, options:retryPromiseOptions<T>) {
    const { retryIf = (_:T) => false, retryCatchIf= (_:T) => true, retries = 1} = options
    let _promise = promise();

    for (var i = 1; i < retries; i++)
        _promise = _promise.catch((value) => retryCatchIf(value) ? promise() : Promise.reject(value))
           .then((value) => retryIf(value) ? promise() : Promise.reject(value));
    
    return _promise;
}
Run Code Online (Sandbox Code Playgroud)

并以这种方式使用它...

retryPromise(() => fetch(url),{
    retryIf: (response:Response) => true, // you could check before trying again
    retries: 5
}).then( ... my favorite things ... )
Run Code Online (Sandbox Code Playgroud)

我为浏览器上的 fetch API 编写了这个。这不会对 500 发出拒绝。并且我没有实施等待。但是,更重要的是,代码展示了如何使用带有 Promise 的组合来避免递归。

JavaScript 版本:

function retryPromise(promise, options) {
    const { retryIf, retryCatchIf, retries } = { retryIf: () => false, retryCatchIf: () => true, retries: 1, ...options};
    let _promise = promise();

    for (var i = 1; i < retries; i++)
        _promise = _promise.catch((value) => retryCatchIf(value) ? promise() : Promise.reject(value))
           .then((value) => retryIf(value) ? promise() : Promise.reject(value));
    
    return _promise;
}
Run Code Online (Sandbox Code Playgroud)

JavaScript 用法:

retryPromise(() => fetch(url),{
    retryIf: (response) => true, // you could check before trying again
    retries: 5
}).then( ... my favorite things ... )
Run Code Online (Sandbox Code Playgroud)

编辑:添加了 js 版本,添加了 retryCatchIf,修复了循环启动。


Isi*_*osa 5

从官方提取文档:

fetch('/users')
    .then(checkStatus)
    .then(parseJSON)
    .then(function(data) {
          console.log('succeeded', data)
    }).catch(function(error) {
          console.log('request failed', error)
    })
Run Code Online (Sandbox Code Playgroud)

看到那个捕获?将在获取失败时触发,例如,您可以再次获取.

看看承诺https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

编辑:添加应该返回结果的工作示例.尝试过使用Chrome(v.60.0)并且没有使用任何polyfill,也没有使用你提到的软件包(仔细阅读文档后,它似乎只是来自fetch polifyll的一个分支).

function fetchRetry(url, delay, limit, fetchOptions = {}) {
    return new Promise((resolve,reject) => {
        function success(response) {
            resolve(response);
        }
        function failure(error){
            limit--;
            if(limit){
                setTimeout(fetchUrl,delay)
            }
            else {
                // this time it failed for real
                reject(error);
            }
        }
        function finalHandler(finalError){
            throw finalError;
        }
        function fetchUrl() {
            return fetch(url,fetchOptions)
                .then(success)
                .catch(failure)
                .catch(finalHandler);
        }
        fetchUrl();
    });
}

fetchRetry('https://www.google.es',1000,4)  
   .then(function(response){
       if(!response.ok){
           throw new Error('failed!');
       }
       return response;
   })
   .then(function(response){
       console.log(response);
   })
   .catch(function(error){
       console.log(error);
    });
Run Code Online (Sandbox Code Playgroud)

没有测试重试尝试是否返回响应,但我想他们这样做了.

编辑:发现这个包但它取代了fetch API所以我不太确定,https://www.npmjs.com/package/fetch-retry(在第一个google结果中还有两个像这样的包fetch-retry页面...)


gol*_*pot 5

我建议使用一些库进行 promise 重试,例如p-retry

例子:

const pRetry = require('p-retry')
const fetch = require('node-fetch')

async function fetchPage () {
  const response = await fetch('https://stackoverflow.com')

  // Abort retrying if the resource doesn't exist
  if (response.status === 404) {
    throw new pRetry.AbortError(response.statusText)
  }

  return response.blob()
}

;(async () => {
  console.log(await pRetry(fetchPage, {retries: 5}))
})()
Run Code Online (Sandbox Code Playgroud)