Как мне сделать несколько звонков без ошибок 429? - PullRequest
0 голосов
/ 12 февраля 2020

Я столкнулся с проблемой в книге, которую, похоже, не могу понять. К сожалению, у меня нет живой ссылки на нее, поэтому, если бы кто-нибудь мог помочь мне с моим подходом к этому теоретически, я был бы очень признателен.

Процесс:

  • Я получаю из вызова извлечения массив строковых кодов (["abcde", "fghij", "klmno", "pqrst"]).
  • Я хочу сделать ссылку на ссылку с каждым строковым кодом. пример:
fetch('http://my-url/abcde').then(res => res.json()).then(res => res).catch(error => new Error(`Error: ${error}`)); // result: 12345
fetch('http://my-url/fghij').then(res => res.json()).then(res => res).catch(error => new Error(`Error: ${error}`)); // result: 67891
...etc
  • Каждый из вызовов будет давать мне числовой код, как показано на рисунке.
  • Мне нужно получить наибольшее число из 5 и получить код афферентной строки и сделать еще один вызов с этим.

"abcde" => 1234

"fghij" => 5314

"klmno" => 3465

"pqrst" => 7234 <--- winner </p>

fetch('http://my-url/pqrst').then(res => res.json()).then(res => res).catch(error => new Error(`Error: ${error}`));

Что я пробовал:

let codesArr = []; // array of string codes
let promiseArr = []; // array of fetch using each string code in `codesArr`, meant to be used in Promise.all()
let codesObj = {}; // object with string code and its afferent number code gotten from the Promise.all()

fetch('http://my-url/some-code')
.then(res => res.json())
.then(res => codesArr = res) // now `codesArr` is ["abcde", "fghij", "klmno", "pqrst"]
.catch(error => new Error(`Error: ${error}`);

for(let i = 0; i < codesArr.length; i++) {  
      promiseArr.push(
         fetch(`http://my-url/${codesArr[i]}`)
            .then(res => res.text())
            .then(res => {
               codesObj[codesArr[i]] = res; 
                        // This is to get an object from which I can later get the highest number and its string code. Like this:
                        // codesObj = {
                        //  "abcde": 12345,
                        //  "fghij": 67891
                        // }
               })
              .catch(error => new Error(`Error: ${error}`)); 
               // I am trying to make an array with fetch, so that I can use it later in Promise.all()
}

Promise.all(promiseArray) // I wanted this to go through all the fetches inside the `promiseArr` and return all of the results at once.
      .then(res => {
         for(let i = 0; i < res.length; i++) {
            console.log(res[i]); 
            // this should output the code number for each call (`12345`, `67891`...etc)
            // this is where I get lost
         }
      })
  • Одна из проблем моего подхода до сих пор кажется, что он делает слишком много запросов, и я получаю 429 ошибку. Я иногда получаю числовые коды хорошо, но не слишком часто.

Ответы [ 2 ]

1 голос
/ 12 февраля 2020

Как вы уже узнали, 429 означает, что вы отправляете слишком много запросов:

429 Слишком много запросов

Пользователь отправил слишком много запросов в заданный промежуток времени («ограничение скорости»).

Представления ответа ДОЛЖНЫ включать подробности, поясняющие условие, и МОГУТ включать заголовок Retry-After, указывающий, как долго ждать перед выполнением нового запроса.

Например:

HTTP/1.1 429 Too Many Requests
Content-Type: text/html
Retry-After: 3600

<html>
  <head>
    <title>Too Many Requests</title>
  </head>
  <body>
    <h1>Too Many Requests</h1>
    <p>I only allow 50 requests per hour to this Web site per
    logged in user. Try again soon.</p>
  </body>
</html>

Обратите внимание, что эта спецификация не определяет, как сервер-источник идентифицирует пользователя и как он считает запросы. Например, исходный сервер, который ограничивает скорости запросов, может делать это на основе количества запросов по каждому ресурсу, по всему серверу или даже среди набора серверов. Аналогичным образом, он может идентифицировать пользователя по его учетным данным для проверки подлинности или по состоянию готовности ie.

Ответы с кодом состояния 429 НЕ ДОЛЖНЫ храниться в кэше.

Кому Чтобы решить эту проблему, вы должны уменьшить количество запросов, сделанных за определенное время. Вам следует перебирать свои коды с задержкой, разнося запрос на несколько секунд. Если не указано в ответе 429, вы должны использовать метод проб и ошибок, чтобы найти задержку, которая работает. В приведенном ниже примере я разнес их на 2 секунды (2000 миллисекунд).

Это можно сделать с помощью setTimeout() для выполнения некоторого фрагмента кода позже, в сочетании с Обещанием создайте функцию sleep. Затем, используя async function сна каждую итерацию в течение определенного c времени.

Примером может быть:

const fetch = createFetchMock({
  "/some-code": ["abcde", "fghij", "klmno", "pqrst"],
  "/abcde": 12345,
  "/fghij": 67891,
  "/klmno": 23456,
  "/pqrst": 78912,
});

async function delayedForEach(array, delay, fn) {
  const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
  for (let i = 0; i < array.length; ++i) {
    await sleep(delay);
    fn(array[i], i, array);
  }
}

async function delayedMap(array, delay, fn) {
  const result = [];
  await delayedForEach(array, delay, (...args) => result.push(fn(...args)));
  return result;
}

fetch("http://my-url/some-code")
.then(respons => respons.json())
.then(codes => {
  return delayedMap(codes, 2000, code => {
    const url = `http://my-url/${code}`;
    console.log("fetching url", url);
    return Promise.all([code, fetch(url).then(response => response.json())]);
  });
})
.then(codeNumberPromises => Promise.all(codeNumberPromises))
.then(codeNumbers => {
  const codesObj = Object.fromEntries(codeNumbers);
  console.log("codesObj:", codesObj);
})
.catch(error => console.error(error));

// fetch mocker factory
function createFetchMock(dataByPath = {}) {
  const empty = new Blob([], {type: "text/plain"});
  
  const status = {
    ok: {status: 200, statusText: "OK"},
    notFound: {status: 404, statusText: "Not Found"}
  };
  
  const blobByPath = Object.create(null);
  for (const path in dataByPath) {
    const json = JSON.stringify(dataByPath[path]);
    blobByPath[path] = new Blob([json], {type: "application/json"});
  }
  
  return function (url) {
    const path = new URL(url).pathname;
    const response = (path in blobByPath)
      ? new Response(blobByPath[path], status.ok)
      : new Response(empty, status.notFound);
    return Promise.resolve(response);
  };
}
1 голос
/ 12 февраля 2020

В этом случае ... Вы должны запускать и ждать каждый fetch запуск fini sh, прежде чем запускать новый fetch, используя async/await

runFetch = async (codesArr) => {
  for(let i = 0; i < codesArr.length; i++){
    const rawResponse = await fetch(`http://my-url/${codesArr[i]}`);
    const codeResponse = rawResponse.json();
    console.log(rawResponse);
    codesObj[codesArr[i]] = codeResponse;
  }
} 

надеюсь, что это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...