web-dev-qa-db-fra.com

Gestion des erreurs HTTP dans Angular 6

J'essaie de gérer l'erreur http à l'aide de la classe ci-dessous dans angular 6. J'ai un statut 401 non autorisé du serveur. Mais cependant, je ne vois pas le message d'erreur de la console.

Fichier HttpErrorsHandler.ts

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

fichier app.module.ts

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

fichier admin.user.component.ts

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;
    });
  }
23
San Jaisy

Pour les demandes XHR, vous devez utiliser un Interceptor

C’est celui que j’utilise pour ajouter JWT aux en-têtes et gérer certaines erreurs de réponse:

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

N'oubliez pas d'enregistrer votre intercepteur dans app.module.ts comme suit:

import { TokenInterceptor } from './auth/token.interceptor';

@NgModule({
  declarations: [],
  imports: [],
  exports: [],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: TokenInterceptor,
      multi: true,
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
35
firegloves

D'après la réponse de @ firegloves, pour que les gestionnaires .pipe de services particuliers puissent réellement catchError leurs propres codes d'échec HTTP, vous devez structurer le code de sorte que:

  1. Si l'intercepteur détecte un code d'erreur HTTP 401, gérez-le et renvoyez of(error), qui peut potentiellement être traité normalement dans les .pipe suivants.
  2. Si le code d'erreur HTTP est un code que l'Interceptor n'est pas conçu pour traiter, throw afin que les gestionnaires d'erreur ultérieurs, comme ceux de vos services, puissent récupérer et gérer les erreurs non-401 pour leurs propres appels.

Mon intercepteur a un double emploi. Il:

  1. Injecte un en-tête Authorization dans toutes les demandes sortantes, si un jeton est stocké.
  2. Intercepte les erreurs HTTP 401 non authentifiées, à quel point le magasin de jetons est invalidé, puis redirige vers /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;
    }

}

Tout ce que AuthService fait est un public/set public qui colle un objet informations d'identification dans localStorage - il s'assure que le jeton n'est pas expiré, mais vous pouvez le concevoir comme vous le souhaitez.

Comme @firegloves indiqué ci-dessus, vous devez ajouter l'intercepteur au pipeline dans 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 { }
9
amphetamachine

exemple de ligne à main d'erreur angular 7

public getstats(param: string, confgId: number, startDate: Date, endDate: Date): Observable<string> {
return this.http.post(this.stats, {
  param: param,
  endDate: endDate
}).pipe(tap((stats: string) => console.log('Got Exceedance Stats : ' + JSON.stringify(stats))),
  catchError(this.handleError<string>('stats')));

}

Ci-dessous le gestionnaire d'erreur

private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
  console.error(error);   
  console.log(`${operation} failed: ${error.message}`);
  return of(result as T);
};

}

entrez le code ici

1
ranki