Angular
处理异常的方式。【相关教学推荐:《angular教学》】什么是Angular
Angualr
是一款来自谷歌的开源的 web 前端框架,诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。
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); } }}
现在,需要更改应用程序的默认行为,以使用我们自定义的类而不是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";// Providersimport { 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, next: HttpHandler): Observable<HttpEvent> { 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";// Providersimport { 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";// Servicesimport { 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";// Servicesimport { 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); } }}
至此,整个错误处理的机制已经介绍完了,基本上跟其他框架或者语言开发的项目处理方式类似。
编程视频!!