Angular中如何实现仅400状态码时重试HTTP请求(最多3次)
解决方案:等待响应后再触发重试请求
你的问题根源在于setInterval是定时触发,不会等待异步HTTP请求的响应返回就会执行下一次回调,而且当前逻辑里的计数器递增时机也不符合“仅400错误才重试”的需求。下面给你两种实用的实现方式:
方式一:基于Promise的递归重试(适配你当前的then/catch写法)
这种方式用递归替代setInterval,只有当请求返回400错误且重试次数未达上限时,才会延迟2秒发起下一次请求,完全等待上一次响应返回后再执行后续逻辑:
private counter = 0; private readonly MAX_RETRIES = 3; // 最大重试次数 private readonly RETRY_DELAY = 2000; // 重试间隔(毫秒) public getMobileNumberCall() { // 启动第一次请求 this.attemptFetchMobileNumber(); } private attemptFetchMobileNumber() { this.commonServices.getDeviceMobileNumber() .then((data: any) => { // 请求成功,清除计数器并处理返回数据 this.counter = 0; console.log('获取设备手机号成功:', data); // 这里可以添加成功后的业务逻辑 }) .catch((err: any) => { // 仅当错误状态码为400且未达最大重试次数时,才进行重试 if (err.status === 400 && this.counter < this.MAX_RETRIES) { this.counter++; console.log(`第${this.counter}次重试,2秒后发起请求`); // 延迟指定时间后递归调用,发起下一次请求 setTimeout(() => { this.attemptFetchMobileNumber(); }, this.RETRY_DELAY); } else { // 要么不是400错误,要么重试次数用尽,处理最终失败 this.counter = 0; // 重置计数器 console.log('请求失败且无法继续重试:', err); // 这里可以添加失败后的业务逻辑 } }); }
逻辑说明:
- 用
attemptFetchMobileNumber作为递归函数,每次请求完成后(成功或失败)才会决定是否发起下一次请求 - 只有在捕获到400错误且重试次数未超过3次时,才会触发延迟重试
- 请求成功或最终失败时,都会重置计数器,避免后续调用时计数混乱
方式二:用RxJS操作符实现(推荐Angular项目使用)
如果你的getDeviceMobileNumber方法返回的是Observable(Angular HttpClient默认返回Observable),可以用RxJS的retryWhen等操作符来更优雅地实现重试逻辑,这也是Angular项目处理异步流的最佳实践:
import { retryWhen, delay, scan, filter, takeWhile } from 'rxjs/operators'; private readonly MAX_RETRIES = 3; private readonly RETRY_DELAY = 2000; public getMobileNumberCall() { this.commonServices.getDeviceMobileNumber() .pipe( retryWhen(errors => errors.pipe( // 只过滤出400错误进行重试 filter(err => err.status === 400), // 累加重试次数,超过上限则抛出错误终止流 scan((retryCount) => { if (retryCount >= this.MAX_RETRIES) { throw new Error('重试次数已达上限'); } return retryCount + 1; }, 0), // 每次重试前延迟指定时间 delay(this.RETRY_DELAY), // 确保重试次数不超过最大值 takeWhile(retryCount => retryCount <= this.MAX_RETRIES) )) ) .subscribe({ next: (data: any) => { console.log('获取设备手机号成功:', data); // 处理成功数据 }, error: (err: any) => { console.log('请求最终失败:', err); // 处理最终失败 } }); }
逻辑说明:
retryWhen会拦截流中的错误,返回一个新的Observable来控制重试逻辑filter确保只有400错误才会触发重试scan用来跟踪重试次数,超过3次时直接抛出错误终止重试delay控制每次重试的间隔时间,保证等待上一次错误响应返回后再发起下一次请求
为什么原来的setInterval不行?
setInterval是定时触发,不管上一次HTTP请求是否完成,到时间就会执行回调,导致多个请求并发- 你的计数器是在定时器回调里直接递增,不管请求成功还是失败都会加,不符合“仅400错误才重试”的需求
内容的提问来源于stack exchange,提问作者vishnu
相关产品推荐
相关产品推荐

