角使用全局拦截器

时间:2019-05-26 17:31:34

标签: javascript angular typescript multipartform-data angular-http-interceptors

我想在全球范围内使用2个拦截器(httpInterceptorProviders,     jwtInterceptorProviders),但在我的惰性模块中不起作用。 我有CoreModule和X延迟加载模块。奇怪的是,我有一个由swagger生成器(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 {}

如果我在petsModule中导出我的2个拦截器,它会拦截请求,但我只想在核心模块中将其导入一次。我签出了这个stackblitz https://stackblitz.com/edit/angular-http-interceptor-working-for-lazy-loaded-module?file=src/app/core/token-interceptor.service.ts,并确保只在我的核心模块中导入HttpClientModule。

1 个答案:

答案 0 :(得分:0)

对于全局使用拦截器,并且提供者位于核心模块中,应添加@Injectable({   providerIn:'root' })在拦截器的顶部,例如此处 https://stackblitz.com/edit/angular-http-interceptor-working-for-lazy-loaded-module?file=src/app/core/token-interceptor.service.ts