Vue中Ajax请求失败后如何实现自动重试?

Dev · 星宇 阅读 73

最近在做数据上报功能时遇到问题,想给axios请求加重试机制。比如网络波动时自动重试3次,但试了setTimeout递归调用,发现每次重试都同时发送了请求,反而更卡了…

这是我的代码片段:

<script>
methods: {
  async sendReport() {
    let retryCount = 0;
    while(retryCount < 3) {
      try {
        await axios.post('/api/report', this.data);
        break;
      } catch(err) {
        setTimeout(() => this.sendReport(), 1000);
        retryCount++;
      }
    }
  }
}
</script>

可是发现第一次失败后会同时触发多次请求,控制台提示”Maximum call stack size exceeded”。哪里出问题了?重试逻辑该怎么改才正确?

我来解答 赞 11 收藏
二维码
手机扫码查看
2 条解答
轩辕玉佩
你这问题出在递归调用和重试逻辑混在一起了,setTimeout里又去调sendReport,但while循环还在继续,导致请求堆积,而且递归太深就爆栈了。

关键点是:重试必须是顺序执行,不能用while循环里套异步+setTimeout这种组合,得用递归但要控制好节奏,或者用async函数自己包一层循环。

代码放这了,改完直接能用:

methods: {
async sendReport(retryCount = 0) {
try {
await axios.post('/api/report', this.data);
} catch (err) {
if (retryCount >= 3) {
console.error('重试3次仍失败', err);
return;
}
await new Promise(resolve => setTimeout(resolve, 1000));
await this.sendReport(retryCount + 1);
}
}
}


或者更稳一点,把axios封装成带重试的实例,以后直接用:

const retryAxios = async (config, maxRetries = 3, delay = 1000) => {
for (let i = 0; i < maxRetries; i++) {
try {
return await axios(config);
} catch (err) {
if (i === maxRetries - 1) throw err;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
};

// 使用
methods: {
async sendReport() {
try {
await retryAxios({
url: '/api/report',
method: 'post',
data: this.data
});
} catch (err) {
console.error('最终失败', err);
}
}
}


别用while里套异步+setTimeout这种写法,容易把自己绕晕,也容易炸栈,用async/await递归或者封装一层更清晰。
点赞 2
2026-02-23 17:54
Good“令敏
你这问题出在递归调用 this.sendReport() 上,每次失败都重新从头开始执行整个函数,相当于无限套娃,不爆栈才怪。而且 setTimeout 是异步的,根本不会等它执行完就继续循环了,retryCount 也完全没起作用。

要实现重试机制,核心是:请求失败后等待一段时间再重试,不是立刻递归调用整个方法。下面是改好的代码,直接复制这个:

async sendReport() {
const maxRetries = 3;
for (let i = 0; i < maxRetries; i++) {
try {
await axios.post('/api/report', this.data);
return; // 成功就退出
} catch (err) {
if (i === maxRetries - 1) throw err; // 最后一次失败再抛错
await new Promise(resolve => setTimeout(resolve, 1000)); // 等1秒再重试
}
}
}


关键点:
- 用 for 循环控制重试次数,每次失败只重试当前请求
- 用 await new Promise + setTimeout 实现真正的延迟等待
- 不要再调自己,避免递归堆叠

这样就能做到失败后隔1秒重试,最多3次,不会重复发一堆请求。
点赞 7
2026-02-09 19:03