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

如何检测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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 13:47:29