如何使角度模块忽略核心模块中添加的http拦截器

Ale*_*aru 43 angular-http-interceptors angular

我有一个带有HttpInterceptor的核心模块用于授权处理,我在AppModule中包含了这个模块,这样使用HttpClient的所有其他模块都使用这个拦截器.

@NgModule({
  imports: [],
  declarations: [],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true,
    },
  ]
})
export class CoreModule { }
Run Code Online (Sandbox Code Playgroud)

如何使模块绕过默认拦截器?

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: components,
  providers: [CustomService],
  exports: components,
})
export class ModuleWithoutInterceptorModule { }
Run Code Online (Sandbox Code Playgroud)

小智 107

你可以使用HttpBackend.

例:

import { HttpClient, ..., HttpBackend } from '@angular/common/http';

@Injectable()
export class TestService {

  private httpClient: HttpClient;

  constructor( handler: HttpBackend) { 
     this.httpClient = new HttpClient(handler);
  }
....
Run Code Online (Sandbox Code Playgroud)

通过这种方式,服务不会被AuthInterceptor拦截.

  • @rodney这个解决方案已经在github上大幅提升,核心团队没有反对意见https://github.com/angular/angular/issues/20203#issuecomment-368680437 (6认同)
  • 使用HttpBackend绕过所有拦截器,对吗?是否可以排除某些拦截器,但不能排除其他拦截器? (6认同)
  • 我正在使用 Angular 9,但仍然是一个有效的解决方案 (3认同)
  • @deg你现在是我的英雄!我在代码中使用了APP_INITIALIZER和HTTP_INTERCEPTOR令牌。我的拦截器使用的是在App初始化程序中初始化的值。我的应用程序初始化程序正在创建一个http.get,这反过来又击中了拦截器。你不知道我遇到这个答案有多高兴!... (2认同)
  • 正在使用APP_INITIALIZER通过快速端点获取我的设置,但我的adal受体尚未初始化,因此引发错误。经过大约一个小时的搜索,这解决了我的问题。可以很容易地看到为此创建博客文章。 (2认同)

jon*_*rpe 50

根据GitHub上的这个建议,我们实现了一个简单的标头来识别不应被拦截的请求.在拦截器中:

export const InterceptorSkipHeader = 'X-Skip-Interceptor';

@Injectable()
export class SkippableInterceptor implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.headers.has(InterceptorSkipHeader)) {
      const headers = req.headers.delete(InterceptorSkipHeader);
      return next.handle(req.clone({ headers }));
    }

    ...  // intercept
  }

}
Run Code Online (Sandbox Code Playgroud)

然后,只要您想跳过特定请求的拦截:

const headers = new HttpHeaders().set(InterceptorSkipHeader, '');

this.httpClient
    .get<ResponseType>(someUrl, { headers })
    ...
Run Code Online (Sandbox Code Playgroud)

请注意,使用此方法时,服务(而非拦截器)在拦截器的逻辑应用时选择; 这意味着服务必须"知道"应用程序中的拦截器.根据您的使用情况,最好让拦截器决定何时应用逻辑.


yur*_*zui 5

为了绕过所有拦截器,我们可以按照@deg 的建议使用 HttpBackend。

在其他情况下,我们可以创建 HttpClient 工厂,允许我们从拦截器链中排除拦截器:

import { createHttpClient } from './http-client.factory';
// ...

@Injectable({
  providedIn: 'root'
})
export class TodosApiService {
  http = createHttpClient(this.injector, [Interceptor2]);
//                                        ^^^^^^^^^^^^
//                                    Interceptors to exclude

  constructor(private injector: Injector) { }

  getTodo() {
    // Interceptor2 will be bypassed
    return this.http.get('https://jsonplaceholder.typicode.com/todos')
  }
}
Run Code Online (Sandbox Code Playgroud)

吴运行示例

请注意,您可以通过创建基类来重用此逻辑:

@Injectable()
export class BasicHttpClient {
  protected http = createHttpClient(this.injector, [Interceptor2]);

  constructor(private injector: Injector) { }
}

@Injectable({ providedIn: 'root' })
export class TodosApiService extends BaseHttpClient {

  getTodo() {
    // Interceptor2 will be bypassed
    return this.http.get('https://jsonplaceholder.typicode.com/todos')
  }
}
Run Code Online (Sandbox Code Playgroud)

http-client.factory.ts

import {
  HTTP_INTERCEPTORS,
  HttpBackend,
  HttpClient,
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { Injector, Type } from '@angular/core';

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 HttpInterceptingHandler implements HttpHandler {
  private chain: HttpHandler | null = null;

  constructor(
    private backend: HttpBackend,
    private injector: Injector,
    private interceptorsToExclude: Type<HttpInterceptor>[],
    private intercept?: (req: HttpRequest<any>) => HttpRequest<any>
  ) {}

  handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
    if (this.intercept) {
      req = this.intercept(req);
    }

    if (this.chain === null) {
      const interceptors = this.injector
        .get(HTTP_INTERCEPTORS, [])
        .filter(
          interceptor => !this.interceptorsToExclude.some(interceptorType => interceptor instanceof interceptorType)
        );

      this.chain = interceptors.reduceRight(
        (next, interceptor) => new HttpInterceptorHandler(next, interceptor),
        this.backend
      );
    }
    return this.chain.handle(req);
  }
}

export function createHttpClient(
  injector: Injector,
  excludedInterceptors: Type<HttpInterceptor>[],
  intercept?: (req: HttpRequest<any>) => HttpRequest<any>
) {
  return new HttpClient(
    new HttpInterceptingHandler(injector.get(HttpBackend), injector, excludedInterceptors, intercept)
  );
}
Run Code Online (Sandbox Code Playgroud)


tre*_*bor 5

Angular 12HttpContext开始,这可以通过属性来完成HttpRequest

这种方法很好,因为它不需要任何剥离标头的逻辑,并且可以在每个请求的基础上完成。

export const DISABLE_GLOBAL_EXCEPTION_HANDLING = new HttpContextToken<boolean>(() => false);

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (this.ignoreErrorHandling(request)) {
            return next.handle(request);
        }

        return next.handle(request).pipe(
            catchError((error) => {
                // normal intercepting logic
                return throwError(() => error);
            }),
        );

    private ignoreErrorHandling(request: HttpRequest<any>) {
        return request.context.get(DISABLE_GLOBAL_EXCEPTION_HANDLING);
    }
Run Code Online (Sandbox Code Playgroud)

可以通过添加令牌来禁用单个请求:

this.httpClient.get<ResponseType>(`/api`, {
    context: new HttpContext().set(DISABLE_GLOBAL_EXCEPTION_HANDLING, true),
});
Run Code Online (Sandbox Code Playgroud)