Угловое использование глобального перехватчика - PullRequest
0 голосов
/ 26 мая 2019

Я хочу использовать 2 перехватчика глобально (httpInterceptorProviders, jwtInterceptorProviders), но он не работает в моих ленивых модулях. У меня есть CoreModule и X ленивые модули загрузки. Странная часть заключается в том, что у меня есть автоматически сгенерированный код генератором сваггера (службы http), эти вызовы перехватываются, но когда я использую пользовательский перехватчик служб http, не перехватывает эти запросы.

Index.ts, где я получаю провайдеров

/** Http interceptor providers in outside-in order */
export const httpInterceptorProviders = [
    { provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true }
];

export const jwtInterceptorProviders = [
    { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }
];

CoreModule, я импортирую свои перехватчики в провайдеры

@NgModule({
  imports: [
    // angular
    CommonModule,
    HttpClientModule,
    // ngrx
    StoreModule.forRoot(reducers, { metaReducers }),
    StoreRouterConnectingModule.forRoot(),
    EffectsModule.forRoot([AuthEffects, GoogleAnalyticsEffects]),
    environment.production
      ? []
      : StoreDevtoolsModule.instrument({
          name: "Angular NgRx Material Starter"
        }),

    // 3rd party
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    }),
    ApiModule.forRoot(() => {
      return new Configuration({
        basePath: `${environment.HOST}:${environment.PORT}`,
        apiKeys: { Authorization: "" }
      });
    })
  ],
  declarations: [],
  providers: [
    LocalStorageService,
    AuthGuardService,
    AnimationsService,
    TitleService,

    // retryHttpInterceptorProviders,
    { provide: ErrorHandler, useClass: AppErrorHandler },
    httpInterceptorProviders,
    jwtInterceptorProviders,
    { provide: RouterStateSerializer, useClass: CustomSerializer },
    {
      provide: HAMMER_LOADER,
      useValue: () => new Promise(() => {})
    },
    AnalyticsService,
    LayoutService,
    StateService,
    PetsServiceWithUpload
  ],
  exports: [TranslateModule]
})
export class CoreModule {
  constructor(
    @Optional()
    @SkipSelf()
    parentModule: CoreModule
  ) {
    if (parentModule) {
      throw new Error("CoreModule is already loaded. Import only in AppModule");
    }
  }
}

export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(
    http,
    `${environment.i18nPrefix}/assets/i18n/`,
    ".json"
  );
}

AppModule

@NgModule({
  declarations: [AppComponent, NavigationComponent, ErrorsComponent],
  imports: [
    BrowserAnimationsModule,
    BrowserModule,
    SharedModule,
    AppRoutingModule,
    AuthModule,
    ThemeModule.forRoot(),
    CoreModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Перехватчик

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
    private isRefreshing = false;
    private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
    constructor(private injector: Injector,
        private localstorage: LocalStorageService,
        private authService: AuthService,
        private store: Store<AppState>, ) { }

    intercept(
        request: HttpRequest<any>,
        next: HttpHandler
    ): Observable<HttpEvent<any>> {
        const tokenInfo = this.localstorage.getItem(AUTH_KEY);
        if (tokenInfo) {
            request = this.addToken(request, tokenInfo.token);
        }
        console.log('TCL: JwtInterceptor -> request', request);
        return next.handle(request).pipe(catchError(error => {
            if (error instanceof HttpErrorResponse && error.status === 401) {
                return this.handle401Error(request, next);
            } else {
                return throwError(error);
            }
        }));
    }

    private addToken(request: HttpRequest<any>, token: string): HttpRequest<any> {
        return request.clone({
            setHeaders: {
                'Authorization': `Bearer ${token}`
            }
        });
    }

    private handle401Error(request: HttpRequest<any>, next: HttpHandler) {

        if (!this.isRefreshing) {
            this.isRefreshing = true;
            this.refreshTokenSubject.next(null);
            const tokenInfo = this.localstorage.getItem(AUTH_KEY);
            return this.authService.authRefreshtokenPost({ refreshToken: tokenInfo.refreshToken }).pipe(
                switchMap((tokenRes: any) => {
                    this.isRefreshing = false;
                    this.refreshTokenSubject.next(tokenRes.token);
                    this.localstorage.setItem(AUTH_KEY,
                        { token: tokenRes.token, refreshToken: tokenRes.refreshToken, isAuthenticated: true });
                    return next.handle(this.addToken(request, tokenRes.token));
                }), catchError((error) => {
                    console.log('TCL: JwtInterceptor -> privatehandle401Error -> error', error);
                    this.store.dispatch(new AuthActions.Logout({ refreshToken: tokenInfo.refreshToken }));
                    return next.handle(request);
                }));

        } else {
            return this.refreshTokenSubject.pipe(
                filter(token => token != null),
                take(1),
                switchMap(jwt => {
                    return next.handle(this.addToken(request, jwt));
                }));
        }
    }
}

Модуль отложенной загрузки

@NgModule({
  imports: [
    ThemeModule,
    PetsRoutingModule,
    StoreModule.forFeature("pets", petsReducer),
    TranslateModule.forChild({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      },
      isolate: true
    }),
    EffectsModule.forFeature([PetsEffects]),
    InfiniteScrollModule,
    SharedModule
  ],
  declarations: [
    PetsComponent,
    CreatePetComponent,
    ViewPetComponent,
    FormPetComponent,
    EditPetComponent,
    PetListVirtualComponent
  ],
  providers: []
})
export class PetsModule {}

Если я экспортирую свои 2 перехватчика в pets.Module, он перехватывает запрос, но я хочу импортировать его один раз только в основной модуль. Я извлекаю этот стек https://stackblitz.com/edit/angular-http-interceptor-working-for-lazy-loaded-module?file=src/app/core/token-interceptor.service.ts и гарантирую, что я импортирую только HttpClientModule в свой основной модуль.

1 Ответ

0 голосов
/ 29 мая 2019

Для использования перехватчика во всем мире, а провайдеры в основном модуле должны добавить @Injectable ({ условии в: «корень» }) в верхней части перехватчиков, как здесь https://stackblitz.com/edit/angular-http-interceptor-working-for-lazy-loaded-module?file=src/app/core/token-interceptor.service.ts

...