我在一本书中遇到一个似乎无法弄清的问题。不幸的是,我没有实时链接,所以如果有人可以在理论上帮助我,我将非常感激。
过程:
我从fetch调用中得到了一个字符串代码数组(["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
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错误。有时我会得到正确的数字代码,但不是很常见。
最佳答案
就像您已经发现429一样,意味着您发送了太多请求:
429 Too Many Requests
用户在给定的时间内发送了太多请求(“
限制”)。
响应表示应包括详细说明
条件,并且可以包含一个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>
请注意,此规范未定义原始服务器的方式
识别用户,也不能识别请求计数。例如,
限制请求速率的原始服务器可以基于
整个服务器中每个资源的请求数,
甚至是一组服务器之间。同样,它可以识别用户
通过其身份验证凭据或有状态Cookie。
状态码为429的响应不得由高速缓存存储。
要解决此问题,您应该在设定的时间内减少请求的数量。您应该延迟迭代代码,使请求间隔几秒钟。如果在429响应中未指定,则必须使用反复试验的方法来找到有效的延迟。在下面的示例中,我将它们隔开了2秒(2000毫秒)。
可以通过使用
setTimeout()
稍后执行一些代码,使用combine this with a Promise创建sleep
函数来完成。然后,在每个特定时间使用async function
睡眠进行每次迭代。例如:
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);
};
}