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

Angular中HttpInterceptor如何检测已取消的XHR请求以隐藏加载指示器?

在Angular HttpInterceptor中检测已取消的请求

当然可以解决这个问题!当Chrome取消过于频繁的API调用时,Angular的HttpClient会抛出特定的取消错误,我们可以在HttpInterceptor里捕获这个状态,同时利用RxJS的操作符确保加载指示器总能被正确隐藏。

核心思路

Angular中请求被取消时,会抛出CanceledError(需要从@angular/common/http导入)。另外,RxJS的finalize操作符是关键——它会在Observable完成、出错或者被取消时执行,完美适配我们需要清理加载状态的场景。

完整代码示例

假设你有一个LoadingService来管理加载指示器的显示/隐藏(用计数方式处理多并发请求更可靠),下面是改造后的拦截器:

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpInterceptor,
  HttpErrorResponse,
  HttpResponse
} from '@angular/common/http';
import { finalize, catchError, tap } from 'rxjs/operators';
import { throwError } from 'rxjs';
import { CanceledError } from '@angular/common/http';
import { LoadingService } from './loading.service'; // 你的加载服务

@Injectable()
export class GlobalHttpInterceptor implements HttpInterceptor {
  constructor(private loadingService: LoadingService) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler) {
    // 增加请求计数
    this.loadingService.incrementRequestCount();

    // 500ms后如果请求仍未完成,显示加载指示器
    const showLoadingTimer = setTimeout(() => {
      if (this.loadingService.getRequestCount() > 0) {
        this.loadingService.showLoading();
      }
    }, 500);

    return next.handle(request).pipe(
      // 正常响应完成时的处理
      tap(event => {
        if (event instanceof HttpResponse) {
          // 这里可以做成功响应的额外处理
        }
      }),
      // 捕获错误,包括取消请求的情况
      catchError((error: HttpErrorResponse) => {
        if (error instanceof CanceledError) {
          console.log(`请求已取消: ${request.url}`);
        } else {
          console.error(`请求出错: ${request.url}`, error);
        }
        return throwError(() => error);
      }),
      // 无论请求成功、失败还是取消,最终都会执行这里的逻辑
      finalize(() => {
        clearTimeout(showLoadingTimer);
        // 减少请求计数
        this.loadingService.decrementRequestCount();
        // 当计数为0时,隐藏加载指示器
        if (this.loadingService.getRequestCount() === 0) {
          this.loadingService.hideLoading();
        }
      })
    );
  }
}

关键细节说明

  1. 用计数管理加载状态:避免单个请求取消导致加载指示器提前隐藏,只有当所有请求都完成(包括取消)时才隐藏。
  2. finalize的可靠性:不管请求是正常完成、抛出错误还是被取消,finalize都会执行,确保我们总能清理定时器并更新加载状态。
  3. CanceledError检测:如果你需要对取消的请求做特殊处理(比如日志上报),可以通过instanceof CanceledError精准识别。

配套的LoadingService示例(参考)

为了让拦截器正常工作,你的加载服务可以这样实现:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class LoadingService {
  private requestCount = 0;
  private isLoadingSubject = new BehaviorSubject<boolean>(false);
  public isLoading$ = this.isLoadingSubject.asObservable();

  incrementRequestCount() {
    this.requestCount++;
  }

  decrementRequestCount() {
    this.requestCount = Math.max(0, this.requestCount - 1);
    this.updateLoadingState();
  }

  getRequestCount() {
    return this.requestCount;
  }

  private updateLoadingState() {
    this.isLoadingSubject.next(this.requestCount > 0);
  }
}

这样改造后,不管请求是正常完成、出错还是被Chrome取消,加载指示器都能被正确隐藏啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:03:15