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

Angular 10.2.5中如何自定义HttpClient实现全局加载与日志功能?

解决方案:使用Angular HttpInterceptor实现全局HTTP请求拦截

Angular 支持通过 HttpInterceptor 实现类似.NET Core中自定义HttpClient模板的全局行为控制,这正是你需要的全局请求处理方案。下面是具体实现步骤:

1. 创建全局加载服务(可选但推荐)

先封装一个加载服务来统一管理全屏加载指示器的显示/隐藏,避免并发请求时重复切换状态:

// loading.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

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

  show(): void {
    this.loadingCount++;
    this.isLoading$.next(true);
  }

  hide(): void {
    this.loadingCount--;
    if (this.loadingCount <= 0) {
      this.loadingCount = 0;
      this.isLoading$.next(false);
    }
  }
}

2. 创建HTTP拦截器

实现HttpInterceptor接口,在拦截器中统一处理请求的开始、结束(成功/失败)逻辑:

// http-logging-loading.interceptor.ts
import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpResponse,
  HttpErrorResponse
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap, finalize } from 'rxjs/operators';
import { LoadingService } from './loading.service';

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

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    // 请求发起时:显示加载、打印请求日志
    this.loadingService.show();
    console.log(`[HTTP Request] ${request.method} ${request.urlWithParams}`, request.body);

    return next.handle(request).pipe(
      // 响应成功时打印日志
      tap((event: HttpEvent<unknown>) => {
        if (event instanceof HttpResponse) {
          console.log(`[HTTP Response] ${request.method} ${request.urlWithParams}`, event.body);
        }
      }, (error: HttpErrorResponse) => {
        // 响应失败时打印错误日志
        console.error(`[HTTP Error] ${request.method} ${request.urlWithParams}`, error);
      }),
      // 请求完成(无论成功/失败):隐藏加载
      finalize(() => {
        this.loadingService.hide();
      })
    );
  }
}

3. 注册拦截器到根模块

在你的根模块(通常是AppModule)的providers数组中注册拦截器,让Angular全局生效:

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpLoggingLoadingInterceptor } from './http-logging-loading.interceptor';
import { LoadingService } from './loading.service';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [
    LoadingService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpLoggingLoadingInterceptor,
      multi: true // 允许多个拦截器按顺序执行
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

4. 实现全屏加载指示器组件

创建一个简单的加载组件,订阅LoadingService的状态来全局显示/隐藏:

// loading.component.ts
import { Component } from '@angular/core';
import { LoadingService } from './loading.service';

@Component({
  selector: 'app-loading',
  template: `
    <div *ngIf="isLoading$ | async" class="fullscreen-loader">
      <div class="spinner"></div>
    </div>
  `,
  styles: [`
    .fullscreen-loader {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(255,255,255,0.8);
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 9999;
    }
    .spinner {
      width: 50px;
      height: 50px;
      border: 5px solid #ccc;
      border-top-color: #007bff;
      border-radius: 50%;
      animation: spin 1s linear infinite;
    }
    @keyframes spin {
      to { transform: rotate(360deg); }
    }
  `]
})
export class LoadingComponent {
  isLoading$ = this.loadingService.isLoading$;

  constructor(private loadingService: LoadingService) {}
}

最后把这个组件添加到AppComponent的模板中,确保它能全局渲染:

<!-- app.component.html -->
<app-loading></app-loading>
<router-outlet></router-outlet>
<!-- 其他业务组件内容 -->

关键说明

  • multi: true:如果后续需要添加其他拦截器(比如Token认证拦截),这个配置允许多个拦截器按注册顺序依次执行。
  • finalize操作符:确保无论请求成功还是失败,都会执行隐藏加载的逻辑,避免加载指示器一直停留。
  • 加载计数逻辑:通过loadingCount处理多个并发请求的场景,只有当所有请求都完成时才隐藏加载指示器。

内容的提问来源于stack exchange,提问作者Altay GENÇASLAN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 11:15:37