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

Angular/Ionic HttpRequest拦截器:如何结合AlertController重复请求

嘿,我来帮你实现结合AlertController的请求重试功能!你的拦截器已经有了令牌注入和基础请求处理,只需要在错误流程里加入弹窗重试的逻辑就行,下面是具体的实现方案:

核心思路

我们会在拦截器的错误捕获流程中,针对可重试的错误(比如网络异常、服务器5xx错误、令牌过期等)弹出Alert提示用户选择是否重试;如果用户确认重试,就重新发起原请求。

完整代码实现

下面是补全后的拦截器代码,包含重试弹窗逻辑:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, switchMap } from 'rxjs/operators';
import { AlertController } from '@ionic/angular';
import { Events } from '@ionic/angular';
import { AuthProvider } from './auth.provider';

@Injectable()
export class RequestInterceptor implements HttpInterceptor {
  constructor(
    public injector: Injector,
    public alertCtrl: AlertController,
    public events: Events
  ) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    let token = this.injector.get(AuthProvider).authToken;
    let request = req;

    // 保留你原来的令牌注入逻辑
    if (token) {
      request = req.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`
        }
      });
    }

    // 发起请求并处理错误重试
    return next.handle(request).pipe(
      catchError((error) => {
        // 判断当前错误是否需要触发重试弹窗
        if (!this.shouldTriggerRetry(error)) {
          return of(error);
        }

        // 弹出重试提示,根据用户选择决定是否重试
        return this.presentRetryAlert().pipe(
          switchMap((userWantsRetry) => {
            if (userWantsRetry) {
              // 用户选择重试,重新发起请求
              return next.handle(request);
            }
            // 用户取消,直接返回错误
            return of(error);
          })
        );
      })
    );
  }

  // 自定义判断规则:哪些错误需要触发重试弹窗
  private shouldTriggerRetry(error: any): boolean {
    // 示例规则:网络错误(status=0)、服务器5xx错误、401令牌过期
    return error.status === 0 || (error.status >= 500 && error.status < 600) || error.status === 401;
  }

  // 创建并显示重试Alert弹窗
  private async presentRetryAlert(): Observable<boolean> {
    const alert = await this.alertCtrl.create({
      header: '请求失败',
      message: '遇到网络异常或服务器问题,是否重试当前请求?',
      buttons: [
        {
          text: '取消',
          role: 'cancel',
          handler: () => {}
        },
        {
          text: '重试',
          handler: () => {}
        }
      ]
    });

    await alert.present();
    // 监听弹窗关闭事件,返回用户的选择结果
    const dismissResult = await alert.onDidDismiss();
    // 如果用户没点取消,就视为同意重试
    return dismissResult.role !== 'cancel';
  }
}
关键细节说明
  1. 错误判断逻辑:shouldTriggerRetry方法可以根据你的业务需求调整,比如只针对特定接口、特定错误码开启重试。
  2. 弹窗异步处理:因为AlertController的方法是异步的,我们用async/await处理弹窗的创建和关闭,最后转换成Observable和拦截器的流对接。
  3. 请求复用:重试时直接复用已经注入令牌的request对象,无需重新处理令牌逻辑。
扩展:令牌过期的特殊重试场景

如果是401令牌过期的情况,通常需要先刷新令牌再重试,你可以在错误处理里加入这个逻辑:

// 修改catchError中的逻辑
catchError((error) => {
  if (error.status === 401) {
    // 先尝试刷新令牌
    return this.injector.get(AuthProvider).refreshToken().pipe(
      switchMap((newToken) => {
        // 刷新成功后,更新请求头的令牌并重试
        const updatedRequest = req.clone({
          setHeaders: {
            Authorization: `Bearer ${newToken}`
          }
        });
        return next.handle(updatedRequest);
      }),
      catchError(() => {
        // 刷新令牌失败,弹出登录提示
        return this.presentLoginRequiredAlert();
      })
    );
  } else if (this.shouldTriggerRetry(error)) {
    return this.presentRetryAlert().pipe(
      switchMap((userWantsRetry) => userWantsRetry ? next.handle(request) : of(error))
    );
  }
  return of(error);
})

最后别忘了在你的AppModule中注册拦截器:

@NgModule({
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: RequestInterceptor, multi: true }
  ]
})
export class AppModule {}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:48:12