错误处理是编写代码常常遇见的并且必须解决的需要,很多时候解决异样的逻辑是为了防止程序的解体,之前《浅谈前端异样监控平台实现计划》介绍过异样跟踪,本文将简略介绍 Angular
解决异样的形式。
什么是 Angular
Angualr
是一款来自谷歌的开源的 web 前端框架,诞生于 2009 年,由 Misko Hevery 等人创立,后为 Google 所收买。是一款优良的前端 JS 框架,曾经被用于 Google 的多款产品当中。
AngularJS 是基于申明式编程模式 是用户能够基于业务逻辑进行开发. 该框架基于 HTML 的内容填充并做了双向数据绑定从而实现了主动数据同步机制. 最初, AngularJS 强化的 DOM 操作加强了可测试性.
try/catch
最相熟的的形式,就是在代码中增加 try/catch
块,在 try
中产生谬误,就会被捕捉并且让脚本继续执行。然而,随着应用程序规模的扩充,这种形式将变得无奈治理。
ErrorHandler
Angular
提供了一个默认的ErrorHandler
,能够将谬误音讯打印到控制台,因而能够拦挡这个默认行为来增加自定义的解决逻辑,上面尝试编写错误处理类:
import {ErrorHandler, Injectable} from "@angular/core";
import {HttpErrorResponse} from "@angular/common/http";
@Injectable()
export class ErrorsHandler implements ErrorHandler {handleError(error: Error | HttpErrorResponse) {if (!navigator.onLine) {console.error("Browser Offline!");
} else {if (error instanceof HttpErrorResponse) {if (!navigator.onLine) {console.error("Browser Offline!");
} else {// Handle Http Error (4xx, 5xx, ect.)
console.error("Http Error!");
}
} else {// Handle Client Error (Angular Error, ReferenceError...)
console.error("Client Error!");
}
console.error(error);
}
}
}
通常在
app
下创立一个共享目录shared
,并将此文件放在providers
文件夹中
当初,须要更改应用程序的默认行为,以应用咱们自定义的类而不是 ErrorHandler
。批改app.module.ts
文件,从 @angular/core
导入 ErrorHandler
,并将providers
增加到 @NgModule
模块,代码如下:
import {NgModule, ErrorHandler} from "@angular/core";
import {BrowserModule} from "@angular/platform-browser";
import {FormsModule} from "@angular/forms";
// Providers
import {ErrorsHandler} from "./shared/providers/error-handler";
import {AppComponent} from "./app.component";
@NgModule({imports: [BrowserModule, FormsModule],
declarations: [AppComponent],
providers: [{provide: ErrorHandler, useClass: ErrorsHandler}],
bootstrap: [AppComponent]
})
export class AppModule {}
HttpInterceptor
HttpInterceptor
提供了一种 拦挡 HTTP 申请 / 响应 的办法,就能够在传递它们之前解决。例如,能够在抛出谬误之前重试几次 HTTP 申请。这样,就能够优雅地解决超时,而不用抛出谬误。
还能够在抛出谬误之前查看谬误的状态,应用拦截器,能够查看 401 状态错误码,将用户重定向到登录页面。
import {Injectable} from "@angular/core";
import {HttpEvent, HttpRequest, HttpHandler, HttpInterceptor, HttpErrorResponse} from "@angular/common/http";
import {Observable, throwError} from "rxjs";
import {retry, catchError} from "rxjs/operators";
@Injectable()
export class HttpsInterceptor implements HttpInterceptor {intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {return next.handle(request).pipe(retry(1),
catchError((error: HttpErrorResponse) => {if (error.status === 401) {// 跳转到登录页面} else {return throwError(error);
}
})
);
}
}
同样须要增加到 app.module.ts
中
import {NgModule, ErrorHandler} from "@angular/core";
import {HTTP_INTERCEPTORS} from "@angular/common/http";
import {BrowserModule} from "@angular/platform-browser";
import {FormsModule} from "@angular/forms";
// Providers
import {ErrorsHandler} from "./shared/providers/error-handler";
import {HttpsInterceptor} from "./shared/providers/http-interceptor";
import {AppComponent} from "./app.component";
@NgModule({imports: [BrowserModule, FormsModule],
declarations: [AppComponent],
providers: [{ provide: ErrorHandler, useClass: ErrorsHandler},
{provide: HTTP_INTERCEPTORS, useClass: HttpsInterceptor, multi: true}
],
bootstrap: [AppComponent]
})
export class AppModule {}
多提供者用于创立可扩大服务,其中零碎带有一些默认提供者,也能够注册其余提供者。默认提供程序和其余提供程序的组合将用于驱动零碎的行为。
Notifications
在控制台打印谬误日志对于开发者来说十分敌对,然而对于用户来说则须要一种更加敌对的形式来通知这些谬误何时从 GUI 中产生。依据谬误类型,举荐两个组件:Snackbar
和Dialog
Snackbar
:举荐用于简略的提醒,比方表单短少必填字段或告诉用户可预感的谬误(有效电子邮件、用户名太长等)。Dialog
:当存在未知的服务器端或客户端谬误时,举荐应用这种形式;通过这种形式,能够显示更多的形容,甚至call-to-action
,比方容许用户输出他们的电子邮件来跟踪谬误。
在 shared
文件夹中增加一个服务来解决所有告诉,新建 services
文件夹,创立文件:notification.service.ts
,代码如下:
import {Injectable} from "@angular/core";
import {MatSnackBar} from "@angular/material/snack-bar";
@Injectable({providedIn: "root"})
export class NotificationService {constructor(public snackBar: MatSnackBar) {}
showError(message: string) {this.snackBar.open(message, "Close", { panelClass: ["error"] });
}
}
更新error-handler.ts
,增加NotificationService
:
import {ErrorHandler, Injectable, Injector} from "@angular/core";
import {HttpErrorResponse} from "@angular/common/http";
// Services
import {NotificationService} from "../services/notification.service";
@Injectable()
export class ErrorsHandler implements ErrorHandler {
//Error handling 须要先加载,应用 Injector 手动注入服务
constructor(private injector: Injector) {}
handleError(error: Error | HttpErrorResponse) {const notifier = this.injector.get(NotificationService);
if (!navigator.onLine) {//console.error("Browser Offline!");
notifier.showError("Browser Offline!");
} else {if (error instanceof HttpErrorResponse) {if (!navigator.onLine) {//console.error("Browser Offline!");
notifier.showError(error.message);
} else {// Handle Http Error (4xx, 5xx, ect.)
// console.error("Http Error!");
notifier.showError("Http Error:" + error.message);
}
} else {// Handle Client Error (Angular Error, ReferenceError...)
// console.error("Client Error!");
notifier.showError(error.message);
}
console.error(error);
}
}
}
如果在一个组件中抛出一个谬误,能够看到一个很好的 snackbar
音讯:
日志和谬误跟踪
当然不能冀望用户向报告每个bug
,一旦部署到生产环境中,就不能看到任何控制台日志。因而就须要可能记录谬误的后端服务与自定义逻辑写入数据库或应用现有的解决方案,如Rollbar
、Sentry
、Bugsnag
。
接下来创立一个简略的谬误跟踪服务,创立logging.service.ts
:
import {Injectable} from "@angular/core";
import {HttpErrorResponse} from "@angular/common/http";
@Injectable({providedIn: "root"})
export class LoggingService {constructor() {}
logError(error: Error | HttpErrorResponse) {
// This will be replaced with logging to either Rollbar, Sentry, Bugsnag, ect.
if (error instanceof HttpErrorResponse) {console.error(error);
} else {console.error(error);
}
}
}
将服务增加到 error-handler.ts
中:
import {ErrorHandler, Injectable, Injector} from "@angular/core";
import {HttpErrorResponse} from "@angular/common/http";
// Services
import {NotificationService} from "../services/notification.service";
import {LoggingService} from "../services/logging.service";
@Injectable()
export class ErrorsHandler implements ErrorHandler {
//Error handling 须要先加载,应用 Injector 手动注入服务
constructor(private injector: Injector) {}
handleError(error: Error | HttpErrorResponse) {const notifier = this.injector.get(NotificationService);
const logger = this.injector.get(LoggingService);
if (!navigator.onLine) {//console.error("Browser Offline!");
notifier.showError("Browser Offline!");
} else {if (error instanceof HttpErrorResponse) {if (!navigator.onLine) {//console.error("Browser Offline!");
notifier.showError(error.message);
} else {// Handle Http Error (4xx, 5xx, ect.)
// console.error("Http Error!");
notifier.showError("Http Error:" + error.message);
}
} else {// Handle Client Error (Angular Error, ReferenceError...)
// console.error("Client Error!");
notifier.showError(error.message);
}
// console.error(error);
logger.logError(error);
}
}
}
至此,整个错误处理的机制曾经介绍完了,基本上跟其余框架或者语言开发的我的项目解决形式相似。