【问题标题】:Angular - Navigation in ErrorHandler only works with zone.run()Angular - ErrorHandler 中的导航仅适用于 zone.run()
【发布时间】:2018-02-14 12:49:18
【问题描述】:

我在 Angular(5.2.0 版)中为所有未处理的异常实现了一个全局错误处理程序。

全局错误处理程序如下所示:

import { Router } from '@angular/router';
import { ErrorHandler, Injectable, Injector, NgZone } from '@angular/core';
import { LoggingService } from '../services/logging.service';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {

  private router: Router;

  constructor(injector: Injector, private zone: NgZone, private loggingService: LoggingService) {
    setTimeout(() => {
      this.router = injector.get(Router);
    });
  }

  handleError(error) {
    this.loggingService.logErrorToApi(error);
    this.zone.run(() => this.router.navigate(['/error']));
  }
}

只有当我有电话 this.zone.run(...) 时,路由才有效。 如果我删除此调用,路由只会将路由 error 添加到 URL 并且不显示组件。 ngOnInit 也没有被调用。

如果我必须使用这样的“hack”来让我的路由对我起作用,那么我的应用程序中的某处似乎存在错误配置。

有人知道我需要改变什么才能让它在没有区域调用的情况下运行吗?


我的路线:

const appRoutes: Routes = [
  {
    path: 'error',
    component: ErrorComponent
  },
  {
    path: '',
    component: HomeComponent,
    canActivate: [CookieGuard]
  },
  { path: '**', component: PageNotFoundComponent }
];

@NgModule({
  declarations: [
    AppComponent,
    HeaderComponent,
    FooterComponent,
    HomeComponent,
    PageNotFoundComponent,
    ErrorComponent
  ],
  imports: [
    RouterModule.forRoot(appRoutes, { enableTracing: !environment.production }),
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    HttpClientModule,
    HttpClientXsrfModule,
  ],
  providers: [
    { provide: ErrorHandler, useClass: GlobalErrorHandler },
    ApiHttpClientService,
    AppSettingsService,
    CookieGuard,
    LoggingService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

这是我调用的错误组件:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'error',
  templateUrl: './error.component.html',
  styleUrls: ['./error.component.scss']
})
export class ErrorComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }
}

【问题讨论】:

  • 你试过类似this.injector.get(Router).navigate... 吗?您首先需要将注入的引用保存到 Injector
  • @Jota.Toledo 如果我这样尝试,我会得到相同的行为。错误路由被添加到 url 但视图没有改变。 :(
  • 除了组件没有被渲染,你是否在控制台看到任何错误/日志?
  • @Jota.Toledo 除了导致我的错误处理程序被调用的错误之外,控制台中没有错误。我什至从路由中看到了跟踪(因为启用了跟踪)。在 html 中,组件被部分注入,但没有调用 ngOnInit。
  • 组件有依赖吗?您可以尝试通过 Injector 实例动态解决 ErrorHandler 的所有依赖项吗?你能提供一个最小的例子吗?

标签: angular angular-router angular-errorhandler


【解决方案1】:

错误处理程序中的错误超出了角度区域。

例如:

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
  handleError(error) {
     NgZone.assertInAngularZone(); // This will throw an error
  }
}

因此,必须将导航包装到 ngZone.run() 中是正常的,如果您不这样做,Angular 将无法检测到更改,您最终会得到一个错误的导航和/或无响应的页面。

【讨论】:

    【解决方案2】:

    在从我的应用程序中删除每个服务和模块并将它们一个一个添加回来直到路由再次中断后,我自己发现了这个问题。 BrowserAnimationsModule 模块会导致问题。

    GitHub 上还有一个未解决的问题 => https://github.com/angular/angular/issues/20290

    【讨论】:

      【解决方案3】:

      为了避免创建循环依赖,您的 LoggingService 也应该在 app.module.ts 中的 providers 数组中。

      我有这样的事情:

      providers: [
          CrashReportService,
          { provide: ErrorHandler, useClass: MyErrorHandler},
        ],
      

      【讨论】:

      • 我的 LoggingService 也在提供者列表中。 (我更新了我的问题)
      • 那么你不应该注入injector.get(...只需像这样把它放在你的构造函数中:constructor(private loggingService: LoggingService, ) { }
      • 它可以正常注入 LoggingService 但遗憾的是它并没有解决我的问题。
      【解决方案4】:

      我为解决这个问题所做的事情是致电window.open(url);

      我认为您的路由器无法正常工作,因为当 Angular 应用程序崩溃时,似乎没有任何工作了。至少这是我的经验。

      【讨论】:

      • 如果 Angular 崩溃,会有一个错误堆栈。 Angular 是为创建单页应用程序而设计的,不建议打开另一个标签页...
      • 它不会使用“_self”选项打开另一个选项卡。你做你想做的事。但是我发现向用户展示一个新的未崩溃页面并带有消息比让他挂在那里并带有崩溃页面更好。如果您有更好的解决方案或知道在这种情况下推荐什么,我会很高兴听到它:)
      • @VincentGagnon 你的错误处理程序有同样的问题吗?
      • 我没有任何循环依赖问题,但是关于如果你不把它放在 zone.run() 中错误后不显示的组件的原始问题,我只是使用了我在这里给出的解决方案。 window.open(url, '_self');它也可能感觉像一个黑客,所以我不确定这是要走的路......
      • @VincentGagnon 如果我尝试在错误处理程序中注入路由器,我只会遇到“循环依赖问题”。你能在没有循环依赖问题的情况下注入它吗?
      猜你喜欢
      • 1970-01-01
      • 2018-11-17
      • 1970-01-01
      • 2017-06-19
      • 2017-05-20
      • 2019-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多