以下网址解释了如何在Angular 4中使用http拦截器:https://angular.io/guide/http#intercepting-all-requests-or-responses
但是,我想知道是否有办法选择是否使用拦截器?或者选择使用哪组拦截器?我想实现一组身份验证拦截器,但是,当用户访问不需要用户身份验证的login
,signup
和forget-password
等内容时,我不希望应用这些拦截器
如果需要,我只需要在我的服务中注入一个干净的HttpClient
实例。我不喜欢我只能使用被所有拦截器污染的HttpClient
的单个全局实例的方式。
答案 0 :(得分:1)
我有相同的要求,并提出了以下解决方案。
在模块中,我使用Token如下提供“ HttpClient”。
export const HTTP_NOAUTH = new InjectionToken("http_noauth");
...
providers: [...,
{
provide: HTTP_NOAUTH,
deps: [HttpBackend],
useFactory: (handler: HttpBackend) => {
return new HttpClient(handler);
}
},
{
provide: HTTP_INTERCEPTORS,
useClass: AuthHttpInterceptor,
multi: true
}],
...
然后,当我注入HttpClient并不想使用AuthHttpInterceptor时,我指定了'@Inject(HTTP_NOAUTH)'。
@Injectable({
providedIn: 'root',
})
export class SomeService {
constructor(@Inject(HTTP_NOAUTH) private http: HttpClient) {
...
到目前为止,我发现(可能还有更多)的一个主要漏洞是,这是一个全有或全无的解决方案。它要么具有所有拦截器,要么不具有任何拦截器。可能有可能在Token提供的条目中注入单个拦截器,但我还没有深入研究。
更新:
我现在可以如下选择针对HttpClient的每种配置要排除的拦截器。
import { Observable } from 'rxjs';
import { HttpHandler, HttpEvent, HttpRequest, HttpInterceptor, HttpBackend, HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http';
import { Injector, InjectionToken } from '@angular/core';
export const provideTokenizedHttpClient = (token: InjectionToken<string>, options: { excludes: Function[] } = { excludes: [] }) => {
return {
provide: token,
deps: [HttpBackend, Injector],
useFactory: (backend: HttpBackend, injector: Injector) => {
return new HttpClient(
new HttpDynamicInterceptingHandler(backend, injector, options)
);
}
}
}
class HttpInterceptorHandler implements HttpHandler {
constructor(private next: HttpHandler, private interceptor: HttpInterceptor) { }
handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
return this.interceptor.intercept(req, this.next);
}
}
class HttpDynamicInterceptingHandler implements HttpHandler {
private chain: any = null;
constructor(private backend: HttpBackend, private injector: Injector, private options: { excludes: Function[] } = { excludes: [] }) { }
public handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
if (this.chain === null) {
const interceptors = this.injector.get(HTTP_INTERCEPTORS, [])
.filter(entry => !this.options.excludes.includes(entry.constructor));
this.chain = interceptors.reduceRight((next, interceptor) => {
return new HttpInterceptorHandler(next, interceptor);
}, this.backend);
}
return this.chain.handle(req);
}
}
现在在我的提供程序中,我仅使用以下内容:
providers: [...
provideTokenizedHttpClient(HTTP_NOAUTH, { excludes: [AuthHttpInterceptor] }),
{
provide: HTTP_INTERCEPTORS,
useClass: AppBusyHttpInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: AuthHttpInterceptor,
multi: true
}],
InjectionToken的创建及其在@Inject装饰器上的用法是相同的。
答案 1 :(得分:0)
我有类似的问题,我花了很多时间来解决它。我想让拦截器层独立于拦截器应用(或不应用)逻辑。
我的解决方案是使分离的模块专用于拦截器。拦截器都不包含if
-条件来决定是否应触发。我将此逻辑移至forRoot
方法,该方法专用于将附加配置传递给模块。
示例调用:
InterceptorModule.forRoot([
{
provide: HTTP_INTERCEPTORS,
useClass: MenuInterceptor,
multi: true,
runConditions: [InterceptConditions.WhiteList],
whiteList: ['api/menu']
},
{
provide: HTTP_INTERCEPTORS,
useClass: AuthorizationInterceptor,
multi: true,
runConditions: [InterceptConditions.BlackList],
blackList: ['api/public']
},
]),
就这些。拦截器包含纯逻辑,forRoot
方法包含运行条件。
要使其正常工作,您必须:
ClassProvider
界面示例:
export interface InterceptorClassProvider extends ClassProvider {
runConditions: InterceptConditions[];
whiteList?: string[];
blackList?: string[];
}
forRoot
方法加载所有内容示例:
static forRoot(interceptorProviders: InterceptorClassProvider[]): ModuleWithProviders {
return {
ngModule: CwaCoreInterceptorModule,
providers: [
{ provide: INTERCEPTOR_CONFIG, useValue: interceptorProviders },
...interceptorProviders
],
};
}