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<Object> {
return this.sendRequest(this.baseUrl + url, 'get', null, params)
.map((res) => {
return res as Object
})
.toPromise();
}
post(url, body): Promise<Object> {
return this.sendRequest(this.baseUrl + url, 'post', body)
.map((res) => {
return res as Object
})
.toPromise();
}
patch(url, body): Promise<Object> {
return this.sendRequest(this.baseUrl + url, 'patch', body)
.map((res) => {
return res as Object
})
.toPromise();
}
sendRequest(url, type, body, params = null): Observable<any> {
return this.httpClient[type](url, { params: params }, body)
}
}
Si je reçois une erreur HTTP (c'est-à-dire 404), j'obtiens un méchant message de la console : ERROR Erreur : Non attrapé (dans la promesse) : [objet Object] from core.es5.js. Comment dois-je m'y prendre dans mon cas ?
Vous avez quelques options, en fonction de vos besoins. Si vous voulez gérer les erreurs au cas par cas, ajoutez un catch
à votre requête. Si vous voulez ajouter une solution globale, utilisez HttpInterceptor
.
Ouvrez [ici le plunker de démonstration qui fonctionne][4] pour les solutions ci-dessous.
Dans le cas le plus simple, il suffit d'ajouter un .catch()
ou un .subscribe()
, comme :
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.
Si vous devez gérer les erreurs à un seul endroit, vous pouvez utiliser catch
et retourner une valeur par défaut (ou une réponse vide) au lieu d'échouer complètement. Vous n'avez pas non plus besoin de .map
juste pour faire un cast, vous pouvez utiliser une fonction générique. Source : [Angular.io - Obtenir des détails sur les erreurs][1].
Donc, une méthode 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 <T>, making the method generic
get<T>(url, params): Observable<T> {
return this.httpClient
.get<T>(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<any>({my: "default value..."});
// or simply an empty observable
return Observable.empty<T>();
});
}
}
La gestion de l'erreur permettra à votre application de continuer même si le service à l'URL est en mauvais état.
Cette solution par requête est bonne surtout lorsque vous voulez 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 si vous avez une réponse par défaut globale), la meilleure solution est d'utiliser un intercepteur, comme décrit ci-dessous.
Exécutez le [démonstration fonctionnelle ici][4].
Une fois encore, le [guide Angular.io][2] montre :
Une fonctionnalité majeure de
@angular/common/http
est l'interception, la possibilité de déclarer des intercepteurs qui se situent entre votre application et le backend. Lorsque votre application fait une requête, les intercepteurs la transforment avant de l'envoyer au serveur, et les intercepteurs peuvent transformer la réponse en retour avant que votre application ne la voie. Ceci est utile pour tout, de l'authentification à la journalisation.
Qui, bien sûr, peut être utilisé pour gérer les erreurs d'une manière très simple ([demo plunker ici] [4]) :
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<any>, next: HttpHandler): Observable<HttpEvent<any>> {
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<HttpEvent<any>>();
});
}
}
Fournir votre intercepteur: Le simple fait de déclarer le HttpErrorInterceptor
ci-dessus ne fait pas que votre application l'utilise. Vous devez le [câbler dans votre module d'application][3] 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 {}
Note: Si vous avez à la fois un intercepteur d'erreurs et un traitement local des erreurs, il est naturellement probable qu'aucun traitement local des erreurs ne sera jamais déclenché, puisque l'erreur sera toujours traitée par l'intercepteur avant qu'elle n'atteigne le traitement local des erreurs.
Exécutez le [démo plunker ici][4].
[1] : https://angular.io/guide/http#getting-error-details [2] : https://angular.io/guide/http#intercepting-all-requests-or-responses [3] : https://angular.io/guide/http#providing-your-interceptor [4] : https://plnkr.co/edit/ulFGp4VMzrbaDJeGqc6q?p=preview
Vous voulez probablement avoir quelque chose comme ça :
this.sendRequest(...)
.map(...)
.catch((err) => {
//handle your error here
})
Cela dépend fortement de l'utilisation que vous faites de votre service, mais c'est le cas de base.
Suite à la réponse de @acdcjunior, voici comment je l'ai implémenté
service :
get(url, params): Promise<Object> {
return this.sendRequest(this.baseUrl + url, 'get', null, params)
.map((res) => {
return res as Object
}).catch((e) => {
return Observable.of(e);
})
.toPromise();
}
appelant :
this.dataService.get(baseUrl, params)
.then((object) => {
if(object['name'] === 'HttpErrorResponse') {
this.error = true;
//or any handle
} else {
this.myObj = object as MyClass
}
});