基于Axios的Promise递归重试请求问题咨询
问题诊断与修复方案
你的代码存在几个核心问题,直接导致了请求慢、很少返回结果的现象:
1. 没给axios设置超时时间
axios默认不会主动触发超时,如果你没在请求配置里加timeout参数,e.message === GET_IPFS_TIMED_OUT这个判断根本不会生效——所谓的“超时重试”完全没起作用。一旦IPFS网关响应缓慢,axios会一直挂着等待,永远进不了catch分支,这就是函数“很少返回”的主要原因。
2. 无限递归重试无限制
就算超时判断生效了,当前代码会在超时后无限调用getIPFSMedia,没有重试次数上限。要是遇到持续超时的情况,Promise链会一直挂着,甚至可能触发栈溢出,永远拿不到结果。
3. 错误处理有漏洞
遇到非超时错误时,catch分支只打印日志却没返回rejected的Promise,这会让getIPFSMedia在错误场景下返回一个resolved状态的Promise,值是undefined,上层await拿到undefined也无法感知错误。
修复后的代码
// 配置重试上限和超时时间 const MAX_RETRIES = 3; const REQUEST_TIMEOUT = 5000; // 5秒超时 const GET_IPFS_TIMED_OUT = `timeout of ${REQUEST_TIMEOUT}ms exceeded`; const getIPFSMedia = async (url, retryCount = 0) => { try { const response = await axios.get(url, { responseType: 'blob', timeout: REQUEST_TIMEOUT // 强制设置超时 }); return URL.createObjectURL(response.data); } catch (e) { // 仅在超时且还有重试次数时重试 if (e.message === GET_IPFS_TIMED_OUT && retryCount < MAX_RETRIES) { console.log(`请求超时,第${retryCount + 1}次重试...`); return getIPFSMedia(url, retryCount + 1); } else { console.error("获取IPFS文件失败:", e.message); // 抛出错误让上层捕获,避免静默失败 throw e; } } }; const fetchData = async () => { try { const image = await getIPFSMedia(url); console.log(image); // 这里可以处理拿到的文件链接 } catch (e) { // 处理最终失败的情况 console.error("最终获取失败:", e); } };
改进点说明
- 强制设置超时:给axios加
timeout参数,确保超时后能触发重试逻辑,不会无限等待。 - 限制重试次数:通过
retryCount控制最多重试3次,避免无限递归导致的Promise挂起。 - 完善错误处理:非超时错误或重试耗尽时主动抛出错误,让上层能捕获并处理,不会出现“没返回结果”的静默失败。
- 改用async/await:比链式then/catch更直观,容易跟踪重试状态,逻辑更清晰。
另外,你提到直接打开链接能立即获取文件,可能是浏览器对IPFS链接做了缓存,而axios请求默认没带缓存相关头,可以试试在请求配置里加headers: { 'Cache-Control': 'no-cache' },或者检查是不是用了不同的IPFS网关(比如浏览器用本地节点,axios用公共网关)。
内容的提问来源于stack exchange,提问作者No Sarcasm
相关产品推荐
相关产品推荐

