React调用多API触发429错误,求setTimeout正确使用方案
解决React中多API调用触发429 Too Many Requests错误的方案
调用多个API时,并发请求很容易触发服务端的频率限制,返回429错误。用setTimeout给每个请求设置递增的延迟,让请求错开时间发送,就能避免这个问题。以下是具体实现:
核心思路
通过setTimeout为每个API请求设置不同的延迟时间(比如逐个延迟1秒),确保请求不会同时发送,降低触发频率限制的概率。同时要注意清理定时器,避免React组件卸载后出现内存泄漏。
完整代码示例
import { useState, useEffect } from 'react'; const App = () => { const [dataList, setDataList] = useState([]); // 替换成你实际要调用的5个API地址 const apiUrls = [ 'https://api.jikan.moe/v4/top/anime', 'https://api.jikan.moe/v4/top/manga', 'https://api.jikan.moe/v4/characters', 'https://api.jikan.moe/v4/seasons/now', 'https://api.jikan.moe/v4/recommendations/anime' ]; // 单个API请求函数 const fetchSingleApi = async (url, index) => { try { const response = await fetch(url); if (!response.ok) { if (response.status === 429) { console.error(`请求${url}触发频率限制,建议延长延迟时间`); return; } throw new Error(`请求失败:${response.status}`); } const result = await response.json(); // 更新对应位置的数据 setDataList(prev => { const newList = [...prev]; newList[index] = result.data; return newList; }); } catch (err) { console.error(`请求${url}出错:`, err); } }; // 调度所有API请求,逐个添加延迟 const loadAllData = () => { const timers = []; apiUrls.forEach((url, index) => { // 第1个请求立即发送,第2个延迟1秒,第3个延迟2秒...以此类推 const timerId = setTimeout(() => { fetchSingleApi(url, index); }, index * 1000); timers.push(timerId); }); return timers; }; useEffect(() => { const timers = loadAllData(); // 组件卸载时清理所有定时器,防止内存泄漏 return () => { timers.forEach(timer => clearTimeout(timer)); }; }, []); return ( <div> {dataList.map((data, index) => ( <div key={index}> <h3>第{index+1}组数据</h3> {data ? ( <ul> {data.slice(0, 5).map(item => ( <li key={item.mal_id}>{item.title}</li> ))} </ul> ) : ( <p>加载中...</p> )} </div> ))} </div> ); }; export default App;
关键细节说明
- 延迟时间调整:如果还是触发429,就把
index * 1000里的1000调大(比如改成1500或2000),延长每个请求的间隔时间。 - 定时器清理:在
useEffect的返回函数中用clearTimeout清理所有定时器,避免组件卸载后定时器仍在运行。 - 错误处理:针对429错误做了专门提示,方便你快速调整延迟策略;其他请求错误也会打印日志,便于排查问题。
可选的串行请求方式
如果API限制非常严格,也可以用串行方式发送请求——前一个请求完成后,等待一段时间再发下一个。这种方式总耗时更长,但能确保请求完全错开:
const loadAllDataSerial = async () => { for (let i = 0; i < apiUrls.length; i++) { await fetchSingleApi(apiUrls[i], i); // 每个请求完成后等待1秒再发下一个 await new Promise(resolve => setTimeout(resolve, 1000)); } }; // 在useEffect中调用: useEffect(() => { loadAllDataSerial(); }, []);
内容的提问来源于stack exchange,提问作者Josh Lee
相关产品推荐
相关产品推荐

