延迟加载模块的Angular 4.3拦截器 [英] Angular 4.3 Interceptors for Lazy Loaded Modules

查看:73
本文介绍了延迟加载模块的Angular 4.3拦截器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在延迟加载的功能模块和功能子模块中使用核心模块服务的最佳实践是什么.
根据Angular样式指南,我有以下

What is the best practice to use core module service in lazy loaded feature module and feature child modules.
As per Angular style guide I have the following

 app
   -core
       - core.module.ts
       -logger.service.ts
       -token-interceptor.service.ts
       -authentication.service.ts
   -shared
       -shared.module.ts
   -base module (my feature base , lazy loaded with router-outlet)
     -base.module.ts
     -base.routing.module.ts
     -base
       -base.component.ts
     -admin (lazy loaded , child module of base module)
      -admin.module.ts
      -admin.routing.ts
      -admin-component.ts 
     -report(lazy loaded , child module of base module, sibling of admin)
      -report.module.ts
      -report.routing.ts
      -report-component.ts

如果我在所有功能模块中添加TokenInterceptorService作为提供程序,则HTTP拦截器将起作用. 当我将其添加到App模块中(而不是在延迟加载的功能模块中)时,它不会拦截在延迟加载的功能模块中触发的http请求.

If I add TokenInterceptorService as a provider in all feature module,then HTTP interceptor works. When I add it in App module,(but not in lazy loaded feature module) it does not intercept http request triggered in lazy loaded feature module.

使用核心模块中声明的服务/拦截器的最佳实践是什么.

What is the best practice, of using services/interceptor declared in core module.

app.module.ts

app.module.ts

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
  ],
  imports: [
    BrowserModule,BrowserAnimationsModule, CoreModule, AppRoutingModule, FormsModule
  ], providers: [{ provide: HTTP_INTERCEPTORS, useClass: TokenInterceptorService, multi: true }],
  bootstrap: [AppComponent]
})
export class AppModule { }

app-routing.module.ts

app-routing.module.ts

@NgModule({
    imports: [
        RouterModule.forRoot([
            { path: 'login', component: LoginComponent },
            { path: '', redirectTo: 'base', pathMatch: 'full' },                   
            {  path: 'base', loadChildren: 'app/base/base.module#BaseModule'  }            
        ])
    ],
    exports: [
        RouterModule
    ]
})
export class AppRoutingModule {
}

core.module.ts

core.module.ts

@NgModule({
  imports: [
    CommonModule, HttpModule,  
  ],
  declarations: [],
  providers: [LoggerService, AuthenticationService]
})
export class CoreModule {
  constructor( @Optional() @SkipSelf() parentModule: CoreModule) {
    throwIfAlreadyLoaded(parentModule, 'CoreModule');
  }
}

token-interceptor.service.ts

token-interceptor.service.ts

import { Injectable } from '@angular/core';
    import { Router } from '@angular/router';
    import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http';
    import { Observable } from 'rxjs/Observable';
    import 'rxjs/add/operator/do';

    import { AuthenticationService } from './authentication.service';

    @Injectable()
    export class TokenInterceptorService implements HttpInterceptor {


      constructor(public auth: AuthenticationService, private router: Router) { }

      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        console.log('Adding authorization header')

        request = request.clone({
          setHeaders: { authorization: this.auth.getToken() }
        });
        console.log('Added authorization header')
        return next.handle(request).do(event => { }, (err: HttpErrorResponse) => {
          console.log("Error ===>", err);
          if (err.error instanceof Error) {
            // A client-side or network error occurred. Handle it accordingly.
            console.log('An error occurred:', err.error.message);
          } else if (err.status == 401) {

            console.log('Status 401  unautorized');
            this.router.navigate(['/login']);
          } else {
            // The backend returned an unsuccessful response code.
            // The response body may contain clues as to what went wrong,
            console.log(`Backend returned code ${err.status}, body was: ${err.error}`);
          }

          return Observable.throw(new Error('Your custom error'));
        });;
      }

    }

base.module.ts

base.module.ts

 @NgModule({
      imports: [
        CommonModule, BaseRoutingModule
      ],
      declarations: [BaseComponent],
      providers: [],
    })
    export class BaseModule {


      constructor( @Optional() @SkipSelf() parentModule: BaseModule) {

        if (parentModule) {
          throw new Error(
            'BaseModule is already loaded. Import it in the AppModule only');
        }
      }
    }

base.routing.module.ts

base.routing.module.ts

@NgModule({
    imports: [
        RouterModule.forChild([
            {
                path: '', component: BaseComponent,
                children: [

                    { path: '', redirectTo: 'admin', pathMatch: 'full' },
                    { path: 'admin', loadChildren: 'app/base/admin/admin.module#AdminModule' },                         
                ]
            }])
    ],
    exports: [
        RouterModule
    ]
})
export class BaseRoutingModule {
}

admin.module.ts

admin.module.ts

@NgModule({
  imports: [
    CommonModule, FormsModule, HttpClientModule, AdminRoutingModule,BusyModule
  ],
  declarations: [UserListComponent, UserComponent, MenuListComponent, MenuComponent, CodeListComponent, CodeComponent],
  providers: [CodeService, UserService, MenuService,{ provide: HTTP_INTERCEPTORS, useClass: TokenInterceptorService, multi: true }]
})
export class AdminModule { }

admin.routing.module.ts

admin.routing.module.ts

@NgModule({
    imports: [
        RouterModule.forChild([

            {
                path: '',
                children: [
                    { path: '', redirectTo:'code-list', pathMatch: 'full'  },
                    { path: 'code-list', component: CodeListComponent },
                    { path: 'code/:id', component: CodeComponent },

                    { path: 'user-list', component: UserListComponent },
                    { path: 'user/:id', component: UserComponent },

                    { path: 'menu-list', component: MenuListComponent },
                    { path: 'menu/:id', component: MenuComponent },                    
                ]
            }
        ])
    ],
    exports: [
        RouterModule
    ]
})
export class AdminRoutingModule {
}

推荐答案

您不必为拦截器创建提供程序. 您应该用forRoot()导出CoreModule:

You don't have to create a provider for your interceptor. You should export your CoreModule with forRoot():

@NgModule({
  imports: [
    CommonModule,
    HttpClientModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    }),
    RouterModule.forRoot(
      [],
      {enableTracing: true}
    ),
  ],
  declarations: [],
  providers: [DatePipe]
})
export class CoreModule {
  constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
    if (parentModule) {
      throw new Error(
        'CoreModule is already loaded. Import it in the AppModule only');
    }
  }

  static forRoot(): ModuleWithProviders {
    return {
      ngModule: CoreModule,
      providers: [
        {provide: 'Window', useValue: window},
        {provide: HTTP_INTERCEPTORS, useClass: RequestInterceptor, multi: true},
        SORT_TYPES_PROVIDER,
        ApiService,
        AnimationService,
        BillingService,
        UserService,
        ...
      ]
    };
  }
}

然后将其导入到您的AppModule中,而根本不用考虑CoreModule导入.这只是必须明确使用的地方.您所有的延迟加载模块将通过DI接受您的服务等.

Then import it in your AppModule and forget about CoreModule imports at all. This is only one place it has to be explicitly used. All your lazy loaded modules will take your services etc by DI.

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    SharedModule,
    CoreModule.forRoot(),
    FeaturesModule,
    PublicModule,
    RouterModule.forRoot([])
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}

此外,您无需为每个模块创建单独的路由模块.只需导出RouterModule.forChild返回的内容,并在需要它的模块的imports中使用它即可.

Also you don't need to create a separate routing module for each module. Just export what RouterModule.forChild returns and use it in imports of your module that needs it.

export const publicRouting: ModuleWithProviders = RouterModule.forChild([
  {
    path: 'login',
    pathMatch: 'full',
    component: SignInComponent,
    data: {
      breadcrumb: 'LGN_TL'
    },
    canActivate: [AuthenticatedGuard]
  },
  {
    path: '',
    component: GlobalComponent,
    loadChildren: '../protected/protected.module#ProtectedModule',
    canLoad: [AuthCanLoadGuard]
  },
  {path: '**', component: PageNotFoundComponent}
]);

UPD.路由建议,而不是样式指南.像以前一样使用RoutingModule( https://angular.io/guide/styleguide#angular- ngmodule-names )

UPD. suggestion for routing not a styleguide. Use RoutingModule as before (https://angular.io/guide/styleguide#angular-ngmodule-names)

这篇关于延迟加载模块的Angular 4.3拦截器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆