source

코어 모듈에 추가된 http 인터셉터를 무시하도록 앵글 모듈을 만드는 방법

manysource 2023. 8. 8. 21:41

코어 모듈에 추가된 http 인터셉터를 무시하도록 앵글 모듈을 만드는 방법

권한 부여 처리를 위해 HttpInterceptor가 포함된 코어 모듈이 있으며 이 모듈을 AppModule에 포함합니다. 이 방식으로 HttpClient를 사용하는 다른 모든 모듈이 이 인터셉터를 사용합니다.

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

모듈을 기본 인터셉터로 우회시키는 방법은 무엇입니까?

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

HttpBackend를 사용할 수 있습니다.

예:

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

@Injectable()
export class TestService {

  private httpClient: HttpClient;

  constructor( handler: HttpBackend) { 
     this.httpClient = new HttpClient(handler);
  }

이러한 방식으로 AuthInterceptor는 서비스를 가로채지 않습니다.

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
  }

}

그런 다음 특정 요청에 대한 가로채기를 건너뛸 때마다 다음을 수행합니다.

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

this.httpClient
    .get<ResponseType>(someUrl, { headers })
    ...

이 방법을 사용하면 인터셉터가 아닌 서비스가 인터셉터의 로직이 적용되는 시기를 선택합니다. 즉, 서비스는 응용 프로그램의 인터셉터에 대해 "알고 있어야" 합니다.사용 사례에 따라 인터셉터가 로직을 적용할 시기를 결정하도록 하는 것이 더 나을 수 있습니다.

모든 인터셉트를 우회하기 위해 @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')
  }
}

Ng-run 예제

기본 클래스를 만들어 이 논리를 재사용할 수 있습니다.

@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')
  }
}

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)
  );
}

Angular 12에서, 이것은 다음과 같이 달성될 수 있습니다.HttpContext의 재산.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);
    }

토큰을 추가하여 개별 요청을 비활성화할 수 있습니다.

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

언급URL : https://stackoverflow.com/questions/46469349/how-to-make-an-angular-module-to-ignore-http-interceptor-added-in-a-core-module