Erreurs de capture dans HttpClient angular

J’ai un service de données qui ressemble à ceci:

@Injectable() export class DataService { baseUrl = 'http://localhost' constructor( private httpClient: HttpClient) { } get(url, params): Promise { return this.sendRequest(this.baseUrl + url, 'get', null, params) .map((res) => { return res as Object }) .toPromise(); } post(url, body): Promise { return this.sendRequest(this.baseUrl + url, 'post', body) .map((res) => { return res as Object }) .toPromise(); } patch(url, body): Promise { return this.sendRequest(this.baseUrl + url, 'patch', body) .map((res) => { return res as Object }) .toPromise(); } sendRequest(url, type, body, params = null): Observable { return this.httpClient[type](url, { params: params }, body) } } 

Si j’obtiens une erreur HTTP (par exemple 404), je reçois un message de la console méchant: Erreur ERROR: Uncaught (promis): [Object Object] from core.es5.js Comment puis-je le gérer dans mon cas?

    Vous avez des options en fonction de vos besoins. Si vous souhaitez gérer les erreurs pour chaque demande, ajoutez une catch à votre demande. Si vous souhaitez append une solution globale, utilisez HttpInterceptor .

    Ouvrez ici le démon plunker de travail pour les solutions ci-dessous.

    tl; dr

    Dans le cas le plus simple, il vous suffit d’append un .catch() ou un .subscribe() , par exemple:

     import 'rxjs/add/operator/catch'; // don't forget this, or you'll get a runtime error this.httpClient .get("data-url") .catch((err: HttpErrorResponse) => { // simple logging, but you can do a lot more, see below console.error('An error occurred:', err.error); }); // or this.httpClient .get("data-url") .subscribe( data => console.log('success', data), error => console.log('oops', error) ); 

    Mais il y a plus de détails à cela, voir ci-dessous.

    Méthode (locale) solution: erreur de journal et réponse de secours de retour

    Si vous avez besoin de gérer les erreurs dans un seul endroit, vous pouvez utiliser catch et return une valeur par défaut (ou une réponse vide) au lieu d’échouer complètement. Vous n’avez pas non plus besoin du .map pour lancer, vous pouvez utiliser une fonction générique. Source: Angular.io – Obtenir des détails d’erreur .

    Donc, une .get() générique .get() serait comme:

     import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse } from "@angular/common/http"; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/of'; import 'rxjs/add/observable/empty'; import 'rxjs/add/operator/retry'; // don't forget the imports @Injectable() export class DataService { baseUrl = 'http://localhost'; constructor(private httpClient: HttpClient) { } // notice the , making the method generic get(url, params): Observable { return this.httpClient .get(this.baseUrl + url, {params}) .retry(3) // optionally add the retry .catch((err: HttpErrorResponse) => { if (err.error instanceof Error) { // A client-side or network error occurred. Handle it accordingly. console.error('An error occurred:', err.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 ${err.status}, body was: ${err.error}`); } // ...optionally return a default fallback value so app can continue (pick one) // which could be a default value // return Observable.of({my: "default value..."}); // or simply an empty observable return Observable.empty(); }); } } 

    La gestion de l’erreur vous permettra de continuer l’application même lorsque le service à l’URL est en mauvais état.

    Cette solution par demande est généralement utile lorsque vous souhaitez renvoyer une réponse par défaut spécifique à chaque méthode. Mais si vous ne vous souciez que de l’affichage des erreurs (ou avez une réponse globale par défaut), la meilleure solution consiste à utiliser un intercepteur, comme décrit ci-dessous.

    Exécutez le démon plunker de travail ici .

    Utilisation avancée: Interception de toutes les demandes ou réponses

    Encore une fois, le guide Angular.io montre:

    Une caractéristique majeure de @angular/common/http est l’interception, la capacité de déclarer des intercepteurs situés entre votre application et le backend. Lorsque votre application effectue une requête, les intercepteurs le transforment avant de l’envoyer au serveur, et les intercepteurs peuvent transformer la réponse à son retour avant que votre application ne le voit. Ceci est utile pour tout, de l’authentification à la journalisation.

    Ce qui, bien sûr, peut être utilisé pour traiter les erreurs de manière très simple ( démoniste ici ):

     import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse, HttpErrorResponse } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/of'; import 'rxjs/add/observable/empty'; import 'rxjs/add/operator/retry'; // don't forget the imports @Injectable() export class HttpErrorInterceptor implements HttpInterceptor { intercept(request: HttpRequest, next: HttpHandler): Observable> { return next.handle(request) .catch((err: HttpErrorResponse) => { if (err.error instanceof Error) { // A client-side or network error occurred. Handle it accordingly. console.error('An error occurred:', err.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 ${err.status}, body was: ${err.error}`); } // ...optionally return a default fallback value so app can continue (pick one) // which could be a default value (which has to be a HttpResponse here) // return Observable.of(new HttpResponse({body: [{name: "Default value..."}]})); // or simply an empty observable return Observable.empty>(); }); } } 

    Fournir votre intercepteur: déclarer simplement le HttpErrorInterceptor ci-dessus ne provoque pas son utilisation par votre application. Vous devez le connecter dans votre module d’application en le fournissant comme intercepteur, comme suit:

     import { NgModule } from '@angular/core'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { HttpErrorInterceptor } from './path/http-error.interceptor'; @NgModule({ ... providers: [{ provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true, }], ... }) export class AppModule {} 

    Remarque: Si vous avez à la fois un intercepteur d’erreur et un traitement d’erreur local, il est probable que le traitement des erreurs locales ne sera jamais déclenché, car l’erreur sera toujours traitée par l’intercepteur avant que l’erreur ne soit traitée.

    Exécutez le démon plunker de travail ici .

    Avec l’arrivée de l’API HTTPClient , non seulement l’API HTTPClient été remplacée, mais une nouvelle a été ajoutée, l’API HttpInterceptor .

    Un de ses objectives est d’append un comportement par défaut à toutes les requêtes sortantes HTTP et les réponses entrantes.

    Donc, si vous voulez append un comportement de gestion des erreurs par défaut , append .catch() à toutes vos méthodes http.get / post / etc est extrêmement difficile à gérer.

    Cela pourrait être fait de la manière suivante comme exemple en utilisant un HttpInterceptor :

     import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { _throw } from 'rxjs/observable/throw'; import 'rxjs/add/operator/catch'; /** * Intercepts the HTTP responses, and in case that an error/exception is thrown, handles it * and extract the relevant information of it. */ @Injectable() export class ErrorInterceptor implements HttpInterceptor { /** * Intercepts an outgoing HTTP request, executes it and handles any error that could be sortingggered in execution. * @see HttpInterceptor * @param req the outgoing HTTP request * @param next a HTTP request handler */ intercept(req: HttpRequest, next: HttpHandler): Observable> { return next.handle(req) .catch(errorResponse => { let errMsg: ssortingng; if (errorResponse instanceof HttpErrorResponse) { const err = errorResponse.message || JSON.ssortingngify(errorResponse.error); errMsg = `${errorResponse.status} - ${errorResponse.statusText || ''} Details: ${err}`; } else { errMsg = errorResponse.message ? errorResponse.message : errorResponse.toSsortingng(); } return _throw(errMsg); }); } } /** * Provider POJO for the interceptor */ export const ErrorInterceptorProvider = { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true, }; 

    // app.module.ts

     import { ErrorInterceptorProvider } from 'somewhere/in/your/src/folder'; @NgModule({ ... providers: [ ... ErrorInterceptorProvider, .... ], ... }) export class AppModule {} 

    Quelques informations supplémentaires pour OP: L’appel de http.get / post / etc sans un type fort n’est pas une utilisation optimale de l’API. Votre service devrait ressembler à ceci:

     // These interfaces could be somewhere else in your src folder, not necessarily in your service file export interface FooPost { // Define the form of the object in JSON format that your // expect from the backend on post } export interface FooPatch { // Define the form of the object in JSON format that your // expect from the backend on patch } export interface FooGet { // Define the form of the object in JSON format that your // expect from the backend on get } @Injectable() export class DataService { baseUrl = 'http://localhost' constructor( private http: HttpClient) { } get(url, params): Observable { return this.http.get(this.baseUrl + url, params); } post(url, body): Observable { return this.http.post(this.baseUrl + url, body); } patch(url, body): Observable { return this.http.patch(this.baseUrl + url, body); } } 

    Renvoyer des Promises partir de vos méthodes de service au lieu des Observables est une autre mauvaise décision.

    Et un conseil supplémentaire: si vous utilisez le script TYPE , commencez à utiliser le type de script. Vous perdez l’un des plus grands avantages de la langue: connaître le type de valeur que vous traitez.

    Si vous voulez, à mon avis, un bon exemple de service angular, jetez un coup d’œil à l’essentiel suivant .

    Vous voulez probablement avoir quelque chose comme ça:

     this.sendRequest(...) .map(...) .catch((err) => { //handle your error here }) 

    Cela dépend aussi de la manière dont vous utilisez votre service, mais c’est le cas de base.

    Suite à la réponse de @acdcjunior, voici comment je l’ai implémenté

    un service:

      get(url, params): Promise { return this.sendRequest(this.baseUrl + url, 'get', null, params) .map((res) => { return res as Object }).catch((e) => { return Observable.of(e); }) .toPromise(); } 

    votre interlocuteur:

     this.dataService.get(baseUrl, params) .then((object) => { if(object['name'] === 'HttpErrorResponse') { this.error = true; //or any handle } else { this.myObj = object as MyClass } }); 

    Assez simple (comparé à la façon dont il a été fait avec l’API précédente).

    Source de (copier / coller) le guide officiel Angular

      http .get('/api/items') .subscribe( // Successful responses call the first callback. data => {...}, // Errors will call this callback instead: err => { console.log('Something went wrong!'); } ); 

    Si vous ne parvenez pas à détecter les erreurs avec l’une des solutions fournies ici, il se peut que le serveur ne gère pas les requêtes CORS.

    Dans ce cas, Javascript, et encore moins Angular, peut accéder aux informations d’erreur.

    Recherchez les avertissements dans votre console qui incluent CORB ou Cross-Origin Read Blocking .

    En outre, la syntaxe a été modifiée pour gérer les erreurs (comme décrit dans toutes les autres réponses). Vous utilisez maintenant des opérateurs canalisables, comme ceci:

     this.service.requestsMyInfo(payload).pipe( catcheError(err => { // handle the error here. }) );