Http拦截器在多条件过滤场景下失效问题排查
Http拦截器进度条异常问题
刷新页面或单条件过滤时进度条正常,但通过模态框进行多条件过滤(即使仅选价格单个条件)时,进度条启动后控制台仅打印true,始终不打印结束的false,进度条持续转动直到返回主页。
更新:请求结束后loadings.size仍保持为1。
相关代码
INTERCEPTOR TS
constructor(private loader:LoadingService) {} intercept( request: HttpRequest<unknown>, next: HttpHandler ): Observable<HttpEvent<unknown>> { this.loader.handle(request.url, true); return next .handle(request) .pipe( catchError((error: any) => { console.log(error); this.loader.handle(error.url, true); return error; }) ) .pipe( map((evt: any) => { if (evt instanceof HttpResponse) { this.loader.handle(evt.url!, false); } return evt; }) ); }
Loading Service
loadingEmitter: Subject<boolean> = new Subject<boolean>(); loadings: Map<string, boolean> = new Map<string, boolean>(); constructor() {} handle(url: string, loadingStatus: boolean): void { if (loadingStatus) { this.loadings.set(url, loadingStatus); this.loadingEmitter.next(true); } else if (!loadingStatus && this.loadings.has(url)) { this.loadings.delete(url); } if (this.loadings.size == 0) { this.loadingEmitter.next(false); } }
查询参数过滤页面代码
cards!: any[]; constructor( private route:ActivatedRoute,private filterS:FilterServiceService) {} ngOnInit(): void { this.route.queryParams.subscribe((params) => { if (params['Id']) { this.filterS.filterByCategoryId(params['Id']).subscribe((response:any) => this.cards = response); } else { this.filterS.getByAllCategory(params).subscribe((response:any) => this.cards = response) } }); }
问题根源与修复方案
核心问题
- 错误处理逻辑错误:请求出错时调用
this.loader.handle(error.url, true),相当于给同一个URL重复添加加载状态,后续仅删除一次会导致loadings残留条目。 - 状态结束逻辑不完整:仅在请求成功返回
HttpResponse时处理结束状态,错误场景下不会触发删除操作,导致loadings只增不减。 - 不支持相同URL并发请求:
Map<string, boolean>会被覆盖,并发请求结束后状态处理混乱。
修复后的代码
修改后的INTERCEPTOR TS
import { throwError } from 'rxjs'; import { finalize } from 'rxjs/operators'; constructor(private loader: LoadingService) {} intercept( request: HttpRequest<unknown>, next: HttpHandler ): Observable<HttpEvent<unknown>> { const requestUrl = request.url; this.loader.handle(requestUrl, true); return next.handle(request).pipe( catchError((error: any) => { console.log(error); return throwError(() => error); }), finalize(() => { // 无论成功/失败,统一结束该URL的加载状态 this.loader.handle(requestUrl, false); }) ); }
修改后的Loading Service
loadingEmitter: Subject<boolean> = new Subject<boolean>(); // 改用计数存储,支持相同URL的并发请求 loadings: Map<string, number> = new Map<string, number>(); constructor() {} handle(url: string, loadingStatus: boolean): void { if (loadingStatus) { // 启动请求时计数+1 const currentCount = this.loadings.get(url) || 0; this.loadings.set(url, currentCount + 1); this.loadingEmitter.next(true); } else { // 结束请求时计数-1,减至0则删除条目 const currentCount = this.loadings.get(url) || 0; if (currentCount > 1) { this.loadings.set(url, currentCount - 1); } else { this.loadings.delete(url); } } // 根据是否还有未完成请求,发送对应状态 this.loadingEmitter.next(this.loadings.size > 0); }
优化查询参数页面(避免内存泄漏)
import { Subject, takeUntil } from 'rxjs'; cards!: any[]; private destroy$ = new Subject<void>(); constructor( private route: ActivatedRoute, private filterS: FilterServiceService) {} ngOnInit(): void { this.route.queryParams.pipe( takeUntil(this.destroy$) ).subscribe((params) => { if (params['Id']) { this.filterS.filterByCategoryId(params['Id']).subscribe((response: any) => this.cards = response); } else { this.filterS.getByAllCategory(params).subscribe((response: any) => this.cards = response) } }); } ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); }
内容的提问来源于stack exchange,提问作者legates
相关产品推荐
相关产品推荐

