Move error handler to error interceptor.

This commit is contained in:
Spencer Ofwiti 2021-03-21 16:11:05 +03:00
parent b5c9699e2c
commit f12e69b5df
4 changed files with 55 additions and 40 deletions

View File

@ -1,12 +1,16 @@
import {ErrorHandler, Injectable} from '@angular/core'; import {ErrorHandler, Injectable} from '@angular/core';
import {LoggingService} from '@app/_services/logging.service'; import {LoggingService} from '@app/_services/logging.service';
import {HttpErrorResponse} from '@angular/common/http'; import {HttpErrorResponse} from '@angular/common/http';
import {Router} from '@angular/router';
@Injectable() @Injectable()
export class GlobalErrorHandler extends ErrorHandler { export class GlobalErrorHandler extends ErrorHandler {
private sentencesForWarningLogging: string[] = []; private sentencesForWarningLogging: string[] = [];
constructor(private loggingService: LoggingService) { constructor(
private loggingService: LoggingService,
private router: Router
) {
super(); super();
} }
@ -31,15 +35,17 @@ export class GlobalErrorHandler extends ErrorHandler {
} }
logError(error: any): void { logError(error: any): void {
const route = this.router.url;
if (error instanceof HttpErrorResponse) { if (error instanceof HttpErrorResponse) {
this.loggingService.sendErrorLevelMessage( this.loggingService.sendErrorLevelMessage(
`There was an HTTP error. ${error.message}, Status code: ${(error as HttpErrorResponse).status}`, this, {error}); `There was an HTTP error on route ${route}.\n${error.message}.\nStatus code: ${(error as HttpErrorResponse).status}`,
this, {error});
} else if (error instanceof TypeError) { } else if (error instanceof TypeError) {
this.loggingService.sendErrorLevelMessage(`There was a Type error. ${error.message}`, this, {error}); this.loggingService.sendErrorLevelMessage(`There was a Type error on route ${route}.\n${error.message}`, this, {error});
} else if (error instanceof Error) { } else if (error instanceof Error) {
this.loggingService.sendErrorLevelMessage(`There was a general error. ${error.message}`, this, {error}); this.loggingService.sendErrorLevelMessage(`There was a general error on route ${route}.\n${error.message}`, this, {error});
} else { } else {
this.loggingService.sendErrorLevelMessage('Nobody threw an error but something happened!', this, {error}); this.loggingService.sendErrorLevelMessage(`Nobody threw an error but something happened on route ${route}!`, this, {error});
} }
} }

View File

@ -6,26 +6,51 @@ import {
HttpInterceptor, HttpErrorResponse HttpInterceptor, HttpErrorResponse
} from '@angular/common/http'; } from '@angular/common/http';
import {Observable, throwError} from 'rxjs'; import {Observable, throwError} from 'rxjs';
import {catchError} from 'rxjs/operators'; import {catchError, retry} from 'rxjs/operators';
import {ErrorDialogService} from '@app/_services'; import {ErrorDialogService, LoggingService} from '@app/_services';
import {Router} from '@angular/router';
@Injectable() @Injectable()
export class ErrorInterceptor implements HttpInterceptor { export class ErrorInterceptor implements HttpInterceptor {
constructor(private errorDialogService: ErrorDialogService) {} constructor(
private errorDialogService: ErrorDialogService,
private loggingService: LoggingService,
private router: Router
) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(catchError((err: HttpErrorResponse) => { return next.handle(request).pipe(
if (isDevMode()) { retry(1),
this.errorDialogService.openDialog({ catchError((err: HttpErrorResponse) => {
message: err.error.message || err.statusText || 'Unknown Error', let errorMessage;
status: err.status || 0 if (err.error instanceof ErrorEvent) {
}); // A client-side or network error occurred. Handle it accordingly.
} errorMessage = `An error occurred: ${err.error.message}`;
if ([401, 403].indexOf(err.status) !== -1) { this.loggingService.sendErrorLevelMessage(errorMessage, this, {error: err});
location.reload(true); } else {
} // The backend returned an unsuccessful response code.
return throwError(err); // The response body may contain clues as to what went wrong.
})); errorMessage = `Backend returned code ${err.status}, body was: ${JSON.stringify(err.error)}`;
this.loggingService.sendErrorLevelMessage(errorMessage, this, {error: err});
}
if (isDevMode()) {
this.errorDialogService.openDialog({
message: errorMessage || err.error.message || err.statusText || 'Unknown Error',
status: err.status || 0
});
}
switch (err.status) {
case 401: // unauthorized
this.router.navigateByUrl('/auth').then();
break;
case 403: // forbidden
location.reload(true);
break;
}
// Return an observable with a user-facing error message.
return throwError(err);
})
);
} }
} }

View File

@ -6,8 +6,8 @@ import {LoggingService} from '@app/_services/logging.service';
import {MutableKeyStore, MutablePgpKeyStore} from '@app/_pgp'; import {MutableKeyStore, MutablePgpKeyStore} from '@app/_pgp';
import {ErrorDialogService} from '@app/_services/error-dialog.service'; import {ErrorDialogService} from '@app/_services/error-dialog.service';
import {tap} from 'rxjs/operators'; import {tap} from 'rxjs/operators';
import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import {Observable, throwError} from 'rxjs'; import {Observable } from 'rxjs';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -154,7 +154,7 @@ export class AuthService {
return this.httpClient.get(`${environment.publicKeysUrl}`, {responseType: 'text'}) return this.httpClient.get(`${environment.publicKeysUrl}`, {responseType: 'text'})
.pipe(tap( .pipe(tap(
data => { }, data => { },
error => { this.handleError(error, 'Unable to load trusted public keys.'); } error => { this.loggingService.sendErrorLevelMessage('Unable to load trusted public keys.', this, {error}); }
)); ));
} }
@ -163,20 +163,4 @@ export class AuthService {
await this.mutableKeyStore.importPrivateKey(this.privateKey); await this.mutableKeyStore.importPrivateKey(this.privateKey);
} }
} }
// TODO this is from the docs and for reference. Move it somewhere better.
private handleError(error: HttpErrorResponse, customMessage: string): Observable<any> {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong.
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${JSON.stringify(error.error)}`);
}
// Return an observable with a user-facing error message.
return throwError(customMessage);
}
} }

View File

@ -44,7 +44,7 @@ import {MutablePgpKeyStore} from '@app/_pgp';
GlobalErrorHandler, GlobalErrorHandler,
{ provide: ErrorHandler, useClass: GlobalErrorHandler }, { provide: ErrorHandler, useClass: GlobalErrorHandler },
{ provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: HttpConfigInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }, // { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]