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
相关产品推荐
相关产品推荐

