You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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不行?

  1. setInterval是定时触发,不管上一次HTTP请求是否完成,到时间就会执行回调,导致多个请求并发
  2. 你的计数器是在定时器回调里直接递增,不管请求成功还是失败都会加,不符合“仅400错误才重试”的需求

内容的提问来源于stack exchange,提问作者vishnu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:14:24