如何检测withInterceptors中是否已配置必填拦截器?
如何在用户未提供必填HTTP拦截器时抛出异常?
我开发的库中有一个必填的HTTP拦截器progressInterceptor,用户必须提供它才能让组件正常工作。我希望通过单例服务NgProgressHttpManager实现:当用户忘记添加这个拦截器时,直接抛出异常提示。现有代码如下,请问该如何修改实现需求?
现有代码
拦截器代码
export function progressInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> { return next(req).pipe( finalize(() => { // some code }) ); }
单例服务代码
@Injectable({ providedIn: 'root' }) export class NgProgressHttpManager { constructor() { // Some how I need to access the list of provided interceptors! if (!interceptor instanceof NgProgressInterceptor) { throw new Error('NgProgressInterceptor is not provided. Please add it to the HTTP client interceptors.'); } } }
用户启动代码示例
bootstrapApplication(AppComponent, { providers: [ provideHttpClient( withInterceptors([ // in case user forgot to add 'progressInterceptor' ]) ) ] }).catch(err => console.error(err));
解决方案
由于Angular函数式拦截器体系中无法直接获取已注册的拦截器列表,我们可以通过注入令牌标记+服务验证的方式实现需求,具体步骤如下:
1. 为拦截器创建标记注入令牌
首先定义一个注入令牌,用来标记拦截器是否已被正确注册:
import { InjectionToken } from '@angular/core'; import { Observable, HttpEvent, HttpRequest, HttpHandlerFn } from '@angular/common/http'; export const PROGRESS_INTERCEPTOR_PROVIDED = new InjectionToken<boolean>('PROGRESS_INTERCEPTOR_PROVIDED'); export function progressInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> { return next(req).pipe( finalize(() => { // 原有业务逻辑 }) ); }
2. 封装注册拦截器的辅助函数
为了降低用户的使用成本,同时确保标记令牌和拦截器绑定注册,封装一个统一的注册函数:
import { provideHttpClient, withInterceptors } from '@angular/common/http'; export function provideNgProgressHttp() { return [ provideHttpClient( withInterceptors([progressInterceptor]) ), { provide: PROGRESS_INTERCEPTOR_PROVIDED, useValue: true } ]; }
3. 修改单例服务的验证逻辑
在NgProgressHttpManager中通过注入令牌验证拦截器是否存在,不存在则抛出异常:
import { Injectable, Inject, Optional } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class NgProgressHttpManager { constructor( @Optional() @Inject(PROGRESS_INTERCEPTOR_PROVIDED) private isInterceptorProvided: boolean ) { if (!this.isInterceptorProvided) { throw new Error('NgProgressInterceptor 未提供,请通过 provideNgProgressHttp() 注册该拦截器,或手动将 progressInterceptor 添加到 HTTP 客户端拦截器并同时提供 PROGRESS_INTERCEPTOR_PROVIDED 令牌。'); } } }
4. 用户端使用方式
用户可以直接调用封装好的函数完成注册:
bootstrapApplication(AppComponent, { providers: [ provideNgProgressHttp() ] }).catch(err => console.error(err));
如果用户需要手动注册拦截器,必须同时提供标记令牌,否则会触发异常:
bootstrapApplication(AppComponent, { providers: [ provideHttpClient( withInterceptors([progressInterceptor]) ), { provide: PROGRESS_INTERCEPTOR_PROVIDED, useValue: true } ] }).catch(err => console.error(err));
关键说明
- 使用
@Optional()装饰器避免令牌未注册时触发Angular的注入错误,转而在服务构造函数中抛出更友好的业务异常。 - 封装辅助函数可以减少用户的操作步骤,降低遗漏注册标记的概率。
内容的提问来源于stack exchange,提问作者Murhaf Sousli
相关产品推荐
相关产品推荐

