我正在使用 Angular 2 惰性路由。客户端与 webpack2 捆绑在一起,使用 AOT 和 angular-router-loader 来延迟加载 child 。当浏览器连接时,一切都按预期工作,也就是说,我可以成功地将路由器导航到延迟加载的模块,成功加载 block ,我可以查看组件等。
但是,如果我模拟断开连接(例如,通过使用离线 chrome 开发人员工具选项),路由会如预期的那样失败,因为它无法加载相关 block 。错误是“加载 block [ block 号] 失败”
之后就没有路由命令了,就好像路由器坏了一样。
我尝试使用全局 ErrorHandler 来处理错误。当时的想法是,也许我可以在它破坏路由器之前发现错误,但到那时似乎已经太晚了。当时我发现路由器不工作的错误。
import { Injectable, ErrorHandler, Injector } from '@angular/core';
import { Router } from '@angular/router';
@Injectable()
export class CustomErrorHandler extends ErrorHandler {
constructor(private injector: Injector) {
super(false);
}
private get router(): Router {
return this.injector.get(Router, null);
}
public handleError(error: Error) {
if (/Loading chunk [\d]+ failed/.test(error.message)) {
console.info('Offline mode');
let router = this.router;
if (router) {
router.navigateByUrl('/offline').then(t => console.debug(t+'')).catch(t=> console.debug(t));
} else {
window.location.href = '/';
}
}
}
}
自定义错误处理程序起作用是因为打印了“离线模式”消息。注入(inject)也有效,路由器不为空,但是路由器导航不起作用,路由器 promise 没有解决也没有被拒绝。
我想要完成的是处理错误(例如向用户显示信息性消息),同时让路由器处于工作状态,以便用户稍后可以导航(当互联网连接时恢复)而无需重新加载整个页面。
更新 1:尝试在没有 aot 和 webpack 的情况下重现
为了查看这是否是 Angular 路由器问题,我尝试查看在尝试使用 jit 编译离线工作时会发生什么。我使用了:angular router plunker导航到登录选项卡,切换到离线并按下登录。当客户端试图加载管理模块时,记录了一些“错误:XHR 错误加载”错误。 最终导航失败,但是之后路由导航没有中断。我能够导航到其他选项卡,切换回在线后我什至能够导航到管理员。 也许问题在于 angular-router-loader webpack 插件如何尝试加载模块。
更新 2:似乎是一个已知问题
最佳答案
每次我遛狗并试图在电梯里测试我的网站时,我都会遇到这个错误。令人惊讶的是没有更好的文档来处理错误 - 特别是所有 non solutions in the github issue .
话虽如此,是一个NavigationError
来自路由器的事件。所以你可以拦截它,阻止你的正常错误处理程序运行并显示一个弹出窗口。这个事件的好处是它包含完整的尝试 URL - 而不是无用的 Error: Uncaught (in promise): Error: Loading chunk common failed.
错误。
这就是我想出的。
在app.component.ts
中(必须注入(inject)private router: Router
)
从构造函数中调用 initErrorHandler()
函数。
// filter router events of type NavigationError
navigationError$ = this.router.events.pipe
(filter((e): e is NavigationError => e instanceof NavigationError));
// Keep a reference to the error handled, so we can ignore it later
_errorHandled: any;
initErrorHandler()
{
this.navigationError$.subscribe((evt) =>
{
let showPopup = false;
// handle known error messages that can be retried
if (evt.error.message.startsWith('Loading chunk'))
{
showPopup = true;
}
else
{
debugger; // consider handling other messages
}
if (showPopup) {
// display a popup however you want...
// I use Angular Material, and popup is MY OWN dialog box service
this.popup.showChoicesDialog({
title: 'Network Error',
desc: 'Sorry we were unable to load that page',
fullscreen: true,
choices: [
{
action: () =>
{
// this is the important part - retry URL
this.router.navigateByUrl(evt.url)
},
buttonText: 'Retry'
}
]
});
// mark the error as handled to avoid global handler
this._errorHandled = evt.error;
}
// normal global error handler
this.zone.onError.subscribe((error: any) =>
{
// ignore errors that were already handled but couldn't be cancelled
if (error.rejection === this._errorHandled)
{
this._errorHandled = undefined;
return;
}
// Whatever you want to do here for true unhandled errors
console.warn(error);
});
}
根据您的用户群,您需要改变消息和行为,但一般方法似乎有效。
我还不知道所有可能的 NavigationError 的完整范围,所以现在这只是处理 Loading chunk
错误。如果您发现替代消息错误,请发表评论。
测试时一定要利用“离线”模式。在快速测试中,如果我启用“离线”模式触发错误,然后尝试再次导航,一旦我禁用“离线”,它确实成功导航。
注意:很多关于“ block 错误”的讨论主题都与新部署后的缓存问题有关。我还没有解决这些问题,但错误消息可能会有所不同,因此您可以显示不同的弹出窗口。
关于angular - angular2延迟加载路由失败如何处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41164968/