在Angular路由解析器中用switchMap解决重复HTTP请求问题
解决Angular路由解析器重复HTTP请求问题
问题根源在于:每次触发新的路由导航时,Angular会创建新的解析器实例,每个实例都会发起独立的HTTP请求——单个解析器内部的switchMap无法跨导航实例取消旧请求。要实现"只保留最后一次请求"的效果,需要在ProductService层通过switchMap统一管理请求生命周期,具体实现如下:
1. 修改ProductService,用switchMap管控请求
在服务内部维护一个Subject接收产品ID,通过switchMap自动取消未完成的旧请求,同时缓存最新结果避免重复请求:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, Subject, switchMap, shareReplay, filter } from 'rxjs'; import { Product } from './product.model'; @Injectable({ providedIn: 'root' }) export class ProductService { private readonly productIdSubject = new Subject<number>(); private readonly productData$ = this.productIdSubject.pipe( // 过滤无效ID filter(id => !isNaN(id)), // 切换到新请求,自动取消未完成的旧请求 switchMap(id => this.http.get<Product | undefined>(`/api/products/${id}`)), // 缓存最新结果,相同ID重复请求直接返回缓存 shareReplay(1) ); constructor(private http: HttpClient) {} getById(id: number): Observable<Product | undefined> { this.productIdSubject.next(id); return this.productData$; } }
2. 简化解析器逻辑
保持解析器原有职责:验证ID有效性、确保产品存在才允许导航,无需额外处理请求去重:
import { ResolveFn } from '@angular/router'; import { Product } from './product.model'; import { inject } from '@angular/core'; import { ProductService } from './product.service'; import { EMPTY } from 'rxjs'; export const productResolver: ResolveFn<Product | undefined> = (route) => { const productId = Number(route.paramMap.get('productId')); if (isNaN(productId)) return EMPTY; return inject(ProductService) .getById(productId) .pipe(filter(product => !!product)); };
效果说明
当用户快速点击多个产品时,ProductService会自动取消之前未完成的HTTP请求,仅处理最后一次触发的ID请求;同时解析器仍会严格校验产品是否存在,只有产品有效时才会完成路由导航。
内容的提问来源于stack exchange,提问作者Othmane
相关产品推荐
相关产品推荐

