【问题标题】:Interceptor declared in app.module is not intercepting call from one lazy loaded moduleapp.module 中声明的拦截器没有拦截来自一个延迟加载模块的调用
【发布时间】:2021-03-07 13:20:10
【问题描述】:

我创建了一个拦截器来添加身份验证令牌并在身份验证令牌过期时刷新,如下所示:

@Injectable()
export class CustomInterceptors implements HttpInterceptor {

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
             // ... implementation details
    }

}

我已经在 angular (app.module) 的主模块中注册了这个拦截器,如下所示:

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        RouterModule.forRoot(appRoutes),
        HttpClientModule, 
        MatSnackBarModule,

        // Fuse modules
        FuseModule.forRoot(fuseConfig),
        FuseProgressBarModule,
        FuseSidebarModule,
        FuseThemeOptionsModule,

        // App modules
        LayoutModule,
        LightboxModule
      
    ],
    bootstrap: [
        AppComponent
    ],
    providers: [AuthGuard, UsersService, ErrorService, {
        provide: HTTP_INTERCEPTORS,
        useClass: CustomInterceptors,
        multi: true
    }]
})
export class AppModule {
}

我有两个延迟加载的模块 AModule 和 BModule,如下所示:

-- AModule
const routes: Routes = [
    {
        path: '**',
        component: AComponent,
        resolve: {
            interventions: AService
        }
    }
];

@NgModule({
    declarations: [
        AComponent
    ],
    imports: [
        RouterModule.forChild(routes),
        MatButtonModule,
        MatCheckboxModule,
        MatDatepickerModule,
        MatFormFieldModule,
        MatIconModule,
        MatInputModule,
        MatMenuModule,
        MatRippleModule,
        MatTableModule,
        MatToolbarModule,
        MatSelectModule,
        MatSnackBarModule,
        MatSortModule,
        MatTooltipModule,
        TranslateModule.forChild(),
        MatProgressSpinnerModule,
        MatPaginatorModule,
        FuseSharedModule,
        FuseConfirmDialogModule,
        FuseSidebarModule,
        FuseDeleteInfoModule
    ],
    providers: [
        AsService
    ]
})
export class AModule {
}


--------------------------------------------------------------------


--BModule
const routes: Routes = [
     {
        path: '**',
        component: BComponent,
        resolve: {
            contacts: BService
        }
    },
];

@NgModule({
    declarations: [
        BComponent
    ],
    imports: [
        RouterModule.forChild(routes),
        MatButtonModule,
        MatCheckboxModule,
        MatExpansionModule,
        MatDatepickerModule,
        MatFormFieldModule,
        MatIconModule,
        MatInputModule,
        MatMenuModule,
        MatRippleModule,
        MatTableModule,
        MatToolbarModule,
        MatProgressSpinnerModule,
        MatAutocompleteModule,
        FuseSharedModule,
        MatTabsModule,
        FuseConfirmDialogModule,
        FuseSidebarModule,
        MatSelectModule,
        MatSnackBarModule,
        MatChipsModule,
        MatTableExporterModule,
        MatSortModule,
        MatTooltipModule,
        TranslateModule.forChild(),
        MatPaginatorModule,
        MatRadioModule,
        MatListModule,
        MatExpansionModule,
        MatSidenavModule,
        MatCardModule,
        ReactiveFormsModule,
        FormsModule,    
        GalleryModule,
        LightboxModule,
        
    ],
    providers: [
        BService,  
        // {
        //     provide: HTTP_INTERCEPTORS,
        //     useClass: CustomInterceptors,
        //     multi: true
        // }
    ]
})
export class BModule {
}

两个延迟加载模块的路由如下:

   {
        path: 'A',
        loadChildren: './a/a.module#AModule',
        canActivate: [AuthGuard], 
        data: { roles: ['Administrator', 'Supervisor','Operator']}
    },
    {
        path: 'B',
        loadChildren: './b/b.module#BModule',
        canActivate: [AuthGuard], 
        data: { roles: ['Administrator']}
    }

问题是拦截器对来自 BModule 的调用不起作用,但它对 AModule 的调用成功。

我找到了一个解决方法,在 BModule 的提供程序部分添加拦截器。这是不对的,因为我基本上是在 BModule 中实例化拦截器的另一个对象。我想让 app.module 中声明的拦截器在所有延迟加载的模块之间共享。

对于解决此问题的任何帮助或指导,我将不胜感激。

问候, 兰多。

附言

另一个正在工作的延迟加载模块(让我们称为 C 模块)在有人提交一些更改时像 B 模块一样崩溃。我运行了git diff 来查看导致模块停止工作的差异。结果如下:

 const routes: Routes = [
@@ -134,7 +138,10 @@ const routes: Routes = [
         MatCardModule,
         ReactiveFormsModule,
         MatListModule,
-        FormsModule
+        FormsModule,
+        GalleryModule,
+        LightboxModule,
+        ImageGalleryModule
     ],
     providers: [
        CService,

我做了一些测试,我能够确定拦截器将停止为导入 ImageGalleryModule 的模块工作。以下是ImageGalleryModule:

@NgModule({
    declarations: [
        ImageGalleryComponent
    ],
    imports: [
        MatButtonModule,
        MatCheckboxModule,
        MatDatepickerModule,
        MatFormFieldModule,
        MatIconModule,
        MatInputModule,
        MatMenuModule,
        MatRippleModule,
        MatTableModule,
        MatToolbarModule,
        MatTableExporterModule,
        MatSnackBarModule,
        MatSortModule,
        TranslateModule.forChild(),
        MatPaginatorModule,
        MatTooltipModule,
        MatProgressSpinnerModule,
        FuseSharedModule,
        FuseConfirmDialogModule,
        FuseSidebarModule,
        MatSelectModule,
        MatRadioModule,
        MatListModule,
        MatExpansionModule,
        MatSidenavModule,
        MatChipsModule,
        MatTabsModule,
        MatCardModule,
        MatTooltipModule,
        MatAutocompleteModule,
        FormsModule,
        ReactiveFormsModule,
        GalleryModule,
        LightboxModule,

    ],
    providers: [
        DatePipe,
    ],
    exports:[
        ImageGalleryComponent
    ]
})
export class ImageGalleryModule {
}

奇怪的是,导入此模块会导致拦截器无法工作,因为此模块不会导入或导出 HttpClientModule。

【问题讨论】:

  • 您是否有 stackblitz 或其他要测试的东西?从我所见,您可以拦截所有 http 调用
  • forRoot moduleWithProviders 方法应该可以帮到你。
  • @RandoShtishi 您必须在 SharedModule/CoreModule 中创建 forRoot 方法,并在导入此模块时使用 ShareModule.forRoot() 方法。并确保forRoot 方法具有providers: [InterceptorService]。检查forRoot docs,那里提到的几乎所有内容
  • @RandoShtishi 在这种情况下,请确保您仅在 AppModule 中导入了 HttpClientModule..
  • @RandoShtishi 无论如何,几乎所有时间CoreModule/ShareModule 都会被导入到功能模块中,所以你只需要调用forRoot 方法。不知道你在这里看到了什么错误。

标签: javascript angular typescript angular-http-interceptors


【解决方案1】:

这是一种解决方法,而不是问题的解决方案。所以这不会被标记为已接受的答案。

我将从描述问题开始:

HTTP_INTERCEPTOR 在延迟加载模块导入 HttpClientModule 时被重置。所有拦截器都设置为在 HttpClient 服务的单个实例上工作。延迟加载模块导入HttpClientModule 的那一刻,它会创建一个新的 HttpClient 服务实例。这个新实例被注入到延迟加载模块的所有组件中,并且从这个实例进行的每个调用都不会被 app-module 中声明的拦截器拦截。

就我而言,我搜索了整个项目,除了 app 模块外,没有找到任何 HttpClientModule 的导入。经过数小时的调试,我发现 BModule 和 CModule 导入了 ImageGalleryModule,这是造成这些行为的罪魁祸首。 在ImageGalleryModule中调查后发现模块GalleryModuleLightboxModule导入了HttpClientModule。

当延迟加载模块导入一个导入 HttpClientModule 的模块时,拦截器不再可用,因为为该延迟加载模块创建了一个新的 HttpClient 实例。

解决方法:

我在一个名为 CoreModule 的单独模块中重构了应用程序模块中提供的所有服务,如下所示:

@NgModule({
    imports:[

    ],
    declarations: [
    ],
    providers: [
    ]
})

export class CoreModule {

    static forRoot(): ModuleWithProviders {
        return {
          ngModule: CoreModule,
          providers: [
            AuthGuard, Service A, Service B, Service C, 
            [{ provide: HTTP_INTERCEPTORS, useClass: CustomInterceptors, multi: true }]
          ],
        };
      }
}

之后在 app-module 和延迟加载的模块中导入 CoreModule,如下所示:

@NgModule({
    declarations: [
...
    ],
    imports: [
...
    CoreModule.forRoot(),
...

我不认为这是一个解决方案,因为我们为导入 GalleryModule 的延迟加载模块创建了一个单独的拦截器。我们有三个拦截器实例:

  • 在 app-module 和 AModule 中实例化的拦截器
  • 在 BModule 中实例化的拦截器
  • 在 CModule 中实例化的拦截器

【讨论】:

    猜你喜欢
    • 2018-09-26
    • 1970-01-01
    • 2020-05-24
    • 1970-01-01
    • 1970-01-01
    • 2018-07-10
    • 1970-01-01
    • 2019-04-25
    • 1970-01-01
    相关资源
    最近更新 更多