Hai alcune opzioni, a seconda delle tue esigenze. Se desideri gestire gli errori in base alla richiesta, aggiungi un catch
alla tua richiesta. Se vuoi aggiungere una soluzione globale, usa HttpInterceptor
.
Apri qui il plunker demo funzionante per le soluzioni seguenti.
tl; dr
Nel caso più semplice, dovrai solo aggiungere un .catch()
o un .subscribe()
, come:
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)
);
Ma ci sono più dettagli su questo, vedi sotto.
Metodo (locale) soluzione: registrare l'errore e restituire la risposta di fallback
Se è necessario gestire gli errori in un solo punto, è possibile utilizzare catch
e restituire un valore predefinito (o una risposta vuota) invece di fallire completamente. Inoltre, non hai bisogno del .map
solo cast, puoi usare una funzione generica. Fonte: Angular.io - Recupero dei dettagli sugli errori .
Quindi, un .get()
metodo generico , sarebbe come:
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 gestione dell'errore consentirà alla tua app di continuare anche quando il servizio all'URL è in cattive condizioni.
Questa soluzione per richiesta è utile soprattutto quando si desidera restituire una risposta predefinita specifica a ciascun metodo. Ma se ti interessa solo la visualizzazione degli errori (o hai una risposta predefinita globale), la soluzione migliore è usare un intercettore, come descritto di seguito.
Esegui qui il plunker demo funzionante .
Utilizzo avanzato: intercettazione di tutte le richieste o risposte
Ancora una volta, la guida Angular.io mostra:
Una delle principali caratteristiche di @angular/common/http
è l'intercettazione, la capacità di dichiarare gli intercettori che si trovano tra la tua applicazione e il backend. Quando la tua applicazione effettua una richiesta, gli intercettori la trasformano prima di inviarla al server e gli intercettori possono trasformare la risposta sulla via del ritorno prima che la tua applicazione la veda. Questo è utile per tutto, dall'autenticazione alla registrazione.
Che, ovviamente, può essere utilizzato per gestire gli errori in modo molto semplice ( demo plunker qui ):
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>>();
});
}
}
Fornire il tuo intercettore: la semplice dichiarazione di quanto HttpErrorInterceptor
sopra non fa sì che la tua app lo utilizzi. È necessario collegarlo al modulo dell'app fornendolo come intercettore, come segue:
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 {}
Nota: se si dispone sia di un intercettatore di errori che di una gestione degli errori locale, naturalmente, è probabile che non venga mai attivata alcuna gestione degli errori locali, poiché l'errore verrà sempre gestito dall'interceptor prima che raggiunga la gestione degli errori locale.
Esegui qui il plunker demo funzionante .
return this.httpClient.get<type>(...)
. e poi avere uncatch...
posto fuori servizio dove lo consuma effettivamente perché è lì che costruirà il flusso di osservabili e potrà gestirlo meglio.