net*_*tik 21 initialization typescript angular
我的Angular5应用程序在应用程序初始化期间从后端加载配置文件(APP_INITIALIZER).由于应用程序无法在没有它的情况下运行,我的目标是向用户显示无法加载配置的消息.
providers: [ AppConfig,
{ provide: APP_INITIALIZER, useFactory: (config: AppConfig) => () => config.load(), deps: [AppConfig], multi: true },
{ provide: LocationStrategy, useClass: HashLocationStrategy},
{ provide: ErrorHandler, useClass: GlobalErrorHandler }]
Run Code Online (Sandbox Code Playgroud)
该AppConfig班应该加载从应用程序加载之前的后端服务的配置文件:
@Injectable()
export class AppConfig {
private config: Object = null;
constructor(private http: HttpClient) {}
public getConfig(key: any) {
return this.config[key];
}
public load() {
return new Promise((resolve, reject) => {
this.http.get(environment.serviceUrl + 'config/config')
.catch((error: any) => {
return Observable.throw(error || 'Server error');
})
.subscribe((responseData) => {
this.config = responseData;
this.config['service_endpoint'] = environment.serviceUrl;
resolve(true);
});
});
}
}
Run Code Online (Sandbox Code Playgroud)
全局异常处理程序:
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
constructor( private messageService: MessageService) { }
handleError(error) {
// the AppConfig exception cannot be shown with the growl message since the growl component is within the AppComponent
this.messageService.add({severity: 'error', summary: 'Exception', detail: `Global Exception Handler: ${error.message}`});
throw error;
}
}
Run Code Online (Sandbox Code Playgroud)
如果无法加载配置文件,则会在全局异常处理程序(console.log()中未捕获的HTTPErrorResponse)中抛出,捕获并重新抛出异常,并且加载微调器永远挂起)
由于AppComponent没有加载(这是好的,因为没有配置就不能使用app)并且因为我的消息/"growl"组件是子组件AppComponent,我无法向用户显示消息.
有没有办法index.html在这个阶段在页面中显示消息?我不想将用户重定向到与index.html不同的.html页面,因为用户只需在error.html上重新加载/ f5.
小智 10
在 main.ts 中,我以这种方式更改了引导程序:
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => {
// error should be logged into console by defaultErrorLogger, so no extra logging is necessary here
// console.log(err);
// show error to user
const errorMsgElement = document.querySelector('#errorMsgElement');
let message = 'Application initialization failed';
if (err) {
if (err.message) {
message = message + ': ' + err.message;
} else {
message = message + ': ' + err;
}
}
errorMsgElement.textContent = message;
});
Run Code Online (Sandbox Code Playgroud)
任何发生的异常都会被捕获,并且消息被设置到一个 html 元素中。该元素在 index.html app-root 标签中定义,例如
<app-root><div id="errorMsgElement" style="padding: 20% 0; text-align: center;"></div>
</app-root>
Run Code Online (Sandbox Code Playgroud)
如果引导程序成功,则标记的内容将替换为 angular。
我也没有为类似问题找到好的解决方案,但是作为一种解决方法,这是我的方法:
用一个initialized变量扩展config类:
@Injectable()
export class AppConfig {
public settings: AppSettings = null;
public initialized = false;
public load() {
return new Promise((resolve, reject) => {
this.http.get(environment.serviceUrl + 'config')
.catch((error: any) => {
this.initialized = false;
resolve(error);
return Observable.throw(error || 'Server error');
})
.subscribe((responseData: any) => {
this.settings = responseData;
this.initialized = true;
resolve(true);
});
});
}
}
Run Code Online (Sandbox Code Playgroud)并app.component.html根据该变量显示应用程序或错误消息:
<div *ngIf="!appConfig.initialized">
<b>Failed to load config!</b>
<!-- or <app-config-error-page> -->
</div>
<div *ngIf="appConfig.initialized" #layoutContainer >
<!-- the app content -->
</div>
Run Code Online (Sandbox Code Playgroud)全局异常处理程序:
@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
constructor( private notificationService: NotificationService) { }
handleError(error) {
this.notificationService.error('Exception', `${error.message}`);
return Observable.throw(error);
}
}
Run Code Online (Sandbox Code Playgroud)当然,也可以将具体的错误消息/异常文本存储在config对象中,如果需要,可以在app.component / error.page.component中向用户显示。
我提供的方法略有不同。在我看来,如果我们不能正确初始化它,我们不希望 Angular 应用程序的引导程序继续,因为它无法正常工作。相反,我们只想向用户显示消息,然后停止。
背景:在我的初始化代码中,我必须按特定顺序发出两个异步请求:
我向我的“自己的”Web 服务器(提供 Angular 应用程序的服务器)发出 HTTP 请求,以获取托管我的后端 API的第二个Web 服务器的主机名。
然后我向第二个 Web 服务器发出请求以检索更多配置信息。
如果这些请求中的任何一个失败,那么我需要停止并显示一条消息,而不是 Angular 继续引导过程。
这是在添加新的异常处理之前我的代码的简化版本(请注意,我更喜欢使用Promiseand async/await而不是Observable,但这并不是真正相关):
const appInitializer = (
localConfigurationService: LocalConfigurationService,
remoteConfigurationService: RemoteConfigurationService
): () => Promise<void> => {
return async () => {
try {
const apiHostName = await localConfigurationService.getApiHostName();
await remoteConfigurationService.load(apiHostName);
} catch (e) {
console.error("Failed to initialize the Angular app!", e);
}
};
export const appInitializerProvider = {
provide: APP_INITIALIZER,
useFactory: appInitializer,
deps: [LocalConfigurationService, RemoteConfigurationService],
multi: true
};
Run Code Online (Sandbox Code Playgroud)
该代码会将错误记录到控制台,然后继续引导过程 - 这不是我们想要的。
要修改此代码以 (a) 显示一条消息,以及 (b) 在其轨道上停止引导程序,我在该console.error调用之后立即添加了以下 3 行:
window.document.body.classList.add('failed');
const forever = new Promise(() => { }); // will never resolve
await forever;
Run Code Online (Sandbox Code Playgroud)
第一行简单地将类“失败”添加到文档<body>元素。稍后我们将看到这有什么影响。
其他两行awaitaPromise永远不会解决 - 换句话说,他们永远等待。这会导致 Angular 引导过程停滞,因此 Angular 应用程序永远不会出现。
最后的更改在我的index.html文件中(由浏览器加载的 HTML 文件,其中“包含”Angular 应用程序)。这是我更改之前的样子:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My App</title>
<base href="/">
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
<app-root>元素中的“正在加载...”文本在Angular 应用程序初始化时显示,并在引导过程完成后替换为应用程序内容。
确保“哎呀!” 如果应用程序无法初始化,则会显示消息,我添加了一个<style>带有一些 CSS 样式的块,以及<app-root>元素中的一些额外内容:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My App</title>
<base href="/">
<style type="text/css">
#failure-message {
display: none;
}
body.failed #loading-message {
display: none;
}
body.failed #failure-message {
display: block;
}
</style>
</head>
<body>
<app-root>
<h1 id="loading-message">Loading...</h1>
<h1 id="failure-message">Oops! Something went wrong.</h1>
</app-root>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
所以现在,默认显示“正在加载...”消息(如果初始化成功,将替换为应用程序内容),但是“哎呀!” 如果<body>元素具有failed类,则会显示消息- 这是我们在异常处理程序中添加的内容。
当然,您可以比简单的<h1>标签做得更好——您可以将任何您喜欢的内容放入其中。
所有这些的最终效果是浏览器显示“正在加载...”,然后要么加载 Angular 应用程序,要么将“正在加载...”文本替换为“哎呀!”。
请注意,URL 没有更改,因此如果您在浏览器中点击重新加载,它将从头开始并尝试重新加载 Angular 应用程序 - 这可能是您想要的。
小智 0
我会更新你的初始化程序捕获而不是抛出 toGlobalErrorHandler
this.http.get(environment.serviceUrl + 'config/config')
.catch((error: any) => {
window.location.href = '/relativepath/different.html';
return Observable.throw(error || 'Server error')
})
.subscribe((responseData) => {
this.config = responseData;
this.config['service_endpoint'] = environment.serviceUrl;
resolve(true);
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2279 次 |
| 最近记录: |