Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Http Error Handling in Angular 6

I, am trying to handle the http error using the below class in angular 6. I got a 401 unAuthorized status from server. But however I, don't see the console error message.

HttpErrorsHandler.ts file

import { ErrorHandler, Injectable} from '@angular/core';     @Injectable()     export class HttpErrorsHandler implements ErrorHandler {       handleError(error: Error) {          // Do whatever you like with the error (send it to the server?)          // And log it to the console          console.error('It happens: ', error);       }     } 

http error

app.module.ts file

providers: [{provide: ErrorHandler, useClass: HttpErrorsHandler}], 

HttpCallFile

import { Injectable , Component} from '@angular/core'; import { HttpClient, HttpHeaders } from "@angular/common/http"; import { Observable } from 'rxjs'; import {AuthServiceJwt} from '../Common/sevice.auth.component';  @Injectable() export class GenericHttpClientService {     private readonly baseUrl : string = "**********";       constructor(private httpClientModule: HttpClient , private authServiceJwt : AuthServiceJwt)  {     }      public GenericHttpPost<T>(_postViewModel: T , destinationUrl : string): Observable<T> {         const headers = new HttpHeaders().set('Content-Type', 'application/json; charset=utf-8')             .set('Authorization',`Bearer ${this.authServiceJwt.getToken}`);         return this.httpClientModule.post<T>(this.baseUrl + destinationUrl, _postViewModel, { headers });     }      // This method is to post Data and Get Response Data in two different type     public GenericHttpPostAndResponse<T,TE>(postViewModel: TE, destinationUrl: string): Observable<T> {         const headers = new HttpHeaders().set('Content-Type', 'application/json; charset=utf-8')             .set('Authorization',`Bearer ${this.authServiceJwt.getToken}`);         return this.httpClientModule.post<T>(this.baseUrl + destinationUrl, postViewModel, { headers });     }      // This method is to post Data and Get Response Data in two different type without JWT Token     public GenericHttpPostWithOutToken<T,TE>(postViewModel: TE, destinationUrl: string): Observable<T> {         const headers = new HttpHeaders().set('Content-Type', 'application/json; charset=utf-8');         return this.httpClientModule.post<T>(this.baseUrl + destinationUrl, postViewModel, { headers });     }      public GenericHttpGet<T>(destinationUrl: string): Observable<T> {         const headers = new HttpHeaders().set('Content-Type', 'application/json')             .set('Authorization',`Bearer ${this.authServiceJwt.getToken}`);         return this.httpClientModule.get<T>(this.baseUrl + destinationUrl, { headers });     }      public GenericHttpDelete<T>(destinationUrl: string): Observable<T> {         const headers = new HttpHeaders().set('Content-Type', 'application/json')             .set('Authorization',`Bearer ${this.authServiceJwt.getToken}`);         return this.httpClientModule.delete<T>(this.baseUrl + destinationUrl, { headers });     } } 

admin.user.component.ts file

private getUsersHttpCall(): void {     this.spinnerProgress = true;     this.genericHttpService.GenericHttpGet<GenericResponseObject<UserViewModel[]>>(this.getAdminUserUrl).subscribe(data => {       if (data.isSuccess) {         this.genericResponseObject.data = data.data;         this.dataSource = this.genericResponseObject.data         this.spinnerProgress = false;       }      }, error => {       console.log(error);       this.spinnerProgress = false;     });   } 
like image 937
San Jaisy Avatar asked Jun 21 '18 14:06

San Jaisy


People also ask

How does Angular handle HTTP errors?

When the error occurs in the HTTP Request it is intercepted and invokes the catchError . Inside the catchError you can handle the error and then use throwError to throw it to the service. We then register the Interceptor in the Providers array of the root module using the injection token HTTP_INTERCEPTORS .

How do you perform error handling for HttpClient Angular?

The basic way to handle errors in Angular is to use Angular's HttpClient service along with RxJS operators throwError and catchError. The HTTP request is made, and it returns the data with a response if anything wrong happens then it returns an error object with an error status code.

How does Angular 6 improved error handling when an error is caused by something in a template?

Answer is "By creating flattened versions of Angular modules"


2 Answers

For XHR request you should use an Interceptor

This is the one I use to add JWT to headers and to handle some response errors:

import {Injectable} from '@angular/core'; import {   HttpRequest,   HttpHandler,   HttpEvent,   HttpInterceptor, HttpErrorResponse } from '@angular/common/http'; import {AuthService} from '../service/auth.service'; import {Observable, of} from 'rxjs'; import {Router} from "@angular/router"; import {catchError} from "rxjs/internal/operators";  @Injectable() export class TokenInterceptor implements HttpInterceptor {    constructor(public auth: AuthService, private router: Router) {   }     /**    * intercept all XHR request    * @param request    * @param next    * @returns {Observable<A>}    */   intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {      if (localStorage.getItem('jwtToken')) {       request = request.clone({         setHeaders: {           Authorization: 'Bearer ' + localStorage.getItem('jwtToken')         }       });     }      /**      * continues request execution      */     return next.handle(request).pipe(catchError((error, caught) => {         //intercept the respons error and displace it to the console         console.log(error);         this.handleAuthError(error);         return of(error);       }) as any);   }     /**    * manage errors    * @param err    * @returns {any}    */   private handleAuthError(err: HttpErrorResponse): Observable<any> {     //handle your auth error or rethrow     if (err.status === 401) {       //navigate /delete cookies or whatever       console.log('handled error ' + err.status);       this.router.navigate([`/login`]);       // if you've caught / handled the error, you don't want to rethrow it unless you also want downstream consumers to have to handle it as well.       return of(err.message);     }     throw err;   } } 

Don't forget to register you interceptor into app.module.ts like so:

import { TokenInterceptor } from './auth/token.interceptor';  @NgModule({   declarations: [],   imports: [],   exports: [],   providers: [     {       provide: HTTP_INTERCEPTORS,       useClass: TokenInterceptor,       multi: true,     }   ],   bootstrap: [AppComponent] }) export class AppModule { } 
like image 100
firegloves Avatar answered Sep 20 '22 15:09

firegloves


From @firegloves's answer, in order to have the .pipe handlers in individual services actually be able to catchError their own HTTP failure codes, you will need to structure the code such that:

  1. If the Interceptor detects an HTTP 401 error code, handle it and return of(error) which can potentially be handled normally in any subsequent .pipe's.
  2. If the HTTP error code is one the Interceptor isn't designed to handle, throw it again so subsequent error handlers, like those in your services, can pick up and handle non-401 errors for their own calls.

My Interceptor has a twofold job. It:

  1. Injects an Authorization header into all outgoing requests, if it has a token stored.
  2. Intercepts HTTP 401 Unauthenticated errors, at which point it invalidates the token store, then redirects back to /login.
import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import {     HttpErrorResponse,     HttpEvent,     HttpHandler,     HttpInterceptor,     HttpRequest, } from '@angular/common/http'; import { Observable } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { of } from 'rxjs/observable/of';  import { AuthService } from './auth.service';  @Injectable({     providedIn: 'root', }) export class RequestInterceptor implements HttpInterceptor {      constructor(         private readonly auth: AuthService,         private readonly router: Router,     ) {     }      /**      * @param HttpRequest<any> request - The intercepted request      * @param HttpHandler next - The next interceptor in the pipeline      * @return Observable<HttpEvent<any>>      */     intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {         request = this.addToken(request);         return next.handle(request)             // add error handling             .pipe(                 catchError(                     (error: any, caught: Observable<HttpEvent<any>>) => {                         if (error.status === 401) {                             this.handleAuthError();                             // if you've caught / handled the error, you don't                             // want to rethrow it unless you also want                             // downstream consumers to have to handle it as                             // well.                             return of(error);                         }                         throw error;                     }                 ),             );     }      /**      * Handle API authentication errors.      */     private handleAuthError() {         // clear stored credentials; they're invalid         this.auth.credentials = null;         // navigate back to the login page         this.router.navigate(['/login']);     }      /**      * Add stored auth token to request headers.      * @param HttpRequest<any> request - the intercepted request      * @return HttpRequest<any> - the modified request      */     private addToken(request: HttpRequest<any>): HttpRequest<any> {         const token: string = this.auth.token;         if (token) {             return request.clone({                 setHeaders: {                     Authorization: `Bearer ${token}`,                 },             });         }         return request;     }  } 

All AuthService does is have a public get/set that sticks a credentials object into localStorage - it makes sure the token isn't expired, but you can design it however you want.

Like @firegloves stated above, you must add the Interceptor to the pipeline in app.module.ts:

import { RequestInterceptor } from './auth/request.interceptor';  @NgModule({     declarations: [],     imports: [],     exports: [],     providers: [         {             provide: HTTP_INTERCEPTORS,             useClass: RequestInterceptor,             multi: true,         },     ],     bootstrap: [AppComponent], }) export class AppModule { } 
like image 23
amphetamachine Avatar answered Sep 16 '22 15:09

amphetamachine