Angular 5全局错误处理器中注入Router的实现难题
我之前在Angular项目里也碰到过类似的问题——自定义错误类里想调用Router和Store,但要么依赖未定义,要么不想层层传递构造函数参数搞复杂类签名。给你几个实用的解决方案,都能解决你的痛点:
方案1:利用全局注入器获取依赖
Angular的Injector可以帮你在非注入类中获取已有的服务实例,不用通过构造函数层层传递。你可以先创建一个全局注入器实例,在应用初始化时保存,之后在错误类里直接取用:
首先创建一个注入器服务来保存全局实例:
// injector.service.ts import { Injector } from '@angular/core'; // 全局注入器实例 export let InjectorInstance: Injector; export class InjectorService { constructor(private injector: Injector) { // 初始化时保存注入器引用 InjectorInstance = injector; } }
然后在AppModule里注册这个服务,确保应用启动时就初始化:
// app.module.ts import { NgModule } from '@angular/core'; import { Injector } from '@angular/core'; import { InjectorService, InjectorInstance } from './injector.service'; @NgModule({ providers: [ { provide: InjectorService, useFactory: (injector: Injector) => new InjectorService(injector), deps: [Injector] } ] }) export class AppModule {}
现在你的错误类里就能直接获取Router和Store了:
// custom-error.ts import { InjectorInstance } from './injector.service'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; // 替换成你实际使用的Store类 export class CustomError { constructor(public message: string, public errorCode: number) {} handleError() { // 获取已有的Router和Store实例 const router = InjectorInstance.get(Router); const store = InjectorInstance.get(Store); // 执行页面跳转和Store操作 router.navigate(['/error-page', this.errorCode]); store.dispatch({ type: 'ERROR_TRIGGERED', payload: this }); } }
这种方式完全不用修改错误类的构造函数签名,而且复用的是应用中已有的服务实例,不会出现重复创建的问题。
方案2:拆分职责,错误类存数据,处理逻辑放服务
如果更倾向于Angular的最佳实践,建议把错误数据和处理逻辑分开:自定义错误类只用来封装错误信息,实际的跳转、Store操作交给专门的错误处理服务(这个服务可以正常注入Router和Store)。
首先定义纯数据类的错误类:
// custom-error.ts export class CustomError { constructor(public message: string, public errorCode: number) {} }
然后创建错误处理服务:
// error-handler.service.ts import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; import { CustomError } from './custom-error'; @Injectable({ providedIn: 'root' }) export class ErrorHandlerService { constructor(private router: Router, private store: Store) {} handleError(error: CustomError) { // 在这里统一处理跳转和Store操作 this.router.navigate(['/error', error.errorCode]); this.store.dispatch({ type: 'LOG_ERROR', payload: error }); } }
之后在你的业务服务里,抛出错误后调用这个处理服务即可:
// business.service.ts import { Injectable } from '@angular/core'; import { ErrorHandlerService } from './error-handler.service'; import { CustomError } from './custom-error'; @Injectable({ providedIn: 'root' }) export class BusinessService { constructor(private errorHandler: ErrorHandlerService) {} performOperation() { try { // 你的业务逻辑代码 throw new Error('模拟错误'); } catch (originalError) { const customError = new CustomError('操作失败', 500); this.errorHandler.handleError(customError); } } }
这种方案职责更清晰,错误类保持简洁,也完全避免了多层传递依赖的问题,是我个人比较推荐的方式。
方案3:静态方法结合全局注入器(极简场景)
如果你的错误处理逻辑很简单,不想单独创建服务,可以在错误类里写静态方法,通过全局注入器获取依赖:
// custom-error.ts import { InjectorInstance } from './injector.service'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; export class CustomError { constructor(public message: string) {} static handle(error: CustomError) { const router = InjectorInstance.get(Router); const store = InjectorInstance.get(Store); router.navigate(['/error']); store.dispatch({ type: 'ERROR_OCCURRED', payload: error.message }); } }
调用的时候直接用CustomError.handle(yourError)就行,错误类的构造函数依然保持简洁。
内容的提问来源于stack exchange,提问作者Usman Tahir
相关产品推荐
相关产品推荐

