On angular error handling

Time:2021-7-31

On angular error handling

Error handling is a requirement that we often encounter and must deal with when writing code. Most of the time, the logic to deal with exceptions is to avoid program crash《Implementation scheme of front-end anomaly monitoring platform》Exception tracking has been introduced, which will be briefly introduced in this paperAngularHow to handle exceptions.

What is angular

AngualrIt is an open-source Web front-end framework from Google. It was born in 2009, created by Misko hevery and others, and later acquired by Google. Is an excellent front-end JS framework, which has been used in many Google products.

Angularjs is based on declarative programming mode. Users can develop based on business logic. The framework is based on HTML content filling and two-way data binding, so as to complete the automatic data synchronization mechanism. Finally, the enhanced DOM operation of angularjs enhances testability

try/catch

The most familiar way is to addtry/catchBlock, intryIf an error occurs in, it will be caught and the script will continue to execute. However, as applications grow in size, this approach becomes unmanageable.

ErrorHandler

AngularProvides a defaultErrorHandler, you can print the error message to the console, so you can intercept this default behavior to add custom processing logic. Try to write an error processing class below:

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);
    }
  }
}

Usually inappCreate a shared directory undershared, and put this file inprovidersFolder

Now, we need to change the default behavior of the application to use our custom classes instead ofErrorHandler。 modifyapp.module.tsFiles, from@angular/coreImportErrorHandler, andprovidersAdd to@NgModuleModule, code as follows:

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

HttpInterceptorProvides aIntercept HTTP requests / responsesYou can handle them before passing them. For example, you can retry the HTTP request several times before throwing an error. In this way, the timeout can be handled gracefully without throwing an error.

You can also check the status of the error before throwing the error. Using the interceptor, you can check the 401 status error code and redirect the user to the login page.

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) {
          //Jump to login page
        } else {
          return throwError(error);
        }
      })
    );
  }
}

Also need to add toapp.module.tsin

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 {}

Multiple providers are used to create extensible services, where the system has some default providers, and other providers can be registered. A combination of the default provider and other providers will be used to drive the behavior of the system.

Notifications

Printing error logs on the console is very friendly for developers, but a more friendly way for users to tell when these errors occur from the GUI. According to the error type, two components are recommended:SnackbarandDialog

  • Snackbar: recommended for simple prompts, such as missing required fields in the form or notifying users of foreseeable errors (invalid e-mail, user name too long, etc.).
  • Dialog: this method is recommended when there are unknown server or client errors; In this way, you can display more descriptions and evencall-to-actionFor example, allow users to enter their email to track errors.

staysharedAdd a service to the folder to handle all notifications, and create a new oneservicesFolders, creating files:notification.service.ts, the code is as follows:

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"] });
  }
}

to updateerror-handler.ts, addNotificationService

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 needs to be loaded first. Use the injector to inject the service manually
  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);
    }
  }
}

If you throw an error in a component, you can see a good resultsnackbarMessage:

Logging and error tracking

Of course, you can’t expect users to report to each otherbug, once deployed to the production environment, you cannot see any console logs. Therefore, it is necessary to write back-end services and custom logic that can record errors to the database or use existing solutions, such asRollbarSentryBugsnag

Next, create a simple error tracking servicelogging.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);
    }
  }
}

Add service toerror-handler.tsMedium:

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 needs to be loaded first. Use the injector to inject the service manually
  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);
    }
  }
}

So far, the whole error handling mechanism has been introduced, which is basically similar to the project processing method developed by other frameworks or languages.

Recommended Today

Lua language novice simple tutorial

1、 Foreword Lua is a lightweight and compact scripting language, which is written in standard C language and open in the form of source code. Its design purpose is to be embedded in the application, so as to provide flexible expansion and customization functions for the application. Lua can be applied in game development, independent […]