Sie haben je nach Bedarf einige Optionen. Wenn Sie Fehler pro Anfrage behandeln möchten, fügen Sie catch
Ihrer Anfrage ein hinzu. Wenn Sie eine globale Lösung hinzufügen möchten, verwenden Sie HttpInterceptor
.
Öffnen Sie hier den funktionierenden Demo-Plunker für die folgenden Lösungen.
tl; dr
Im einfachsten Fall müssen Sie nur ein .catch()
oder ein hinzufügen .subscribe()
, wie:
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)
);
Aber es gibt noch mehr Details dazu, siehe unten.
Methode (lokal) Lösung: Fehler protokollieren und Fallback-Antwort zurückgeben
Wenn Sie Fehler nur an einer Stelle behandeln müssen, können Sie catch
einen Standardwert (oder eine leere Antwort) verwenden und zurückgeben, anstatt vollständig fehlzuschlagen. Sie brauchen auch nicht .map
nur das Casting, sondern können eine generische Funktion verwenden. Quelle: Angular.io - Abrufen von Fehlerdetails .
Eine generische .get()
Methode wäre also wie folgt:
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>();
});
}
}
Durch die Behandlung des Fehlers kann die App auch dann fortgesetzt werden, wenn sich der Dienst unter der URL in einem schlechten Zustand befindet.
Diese Lösung pro Anforderung eignet sich vor allem dann, wenn Sie für jede Methode eine bestimmte Standardantwort zurückgeben möchten. Wenn Sie sich jedoch nur für die Fehleranzeige interessieren (oder eine globale Standardantwort haben), ist die bessere Lösung die Verwendung eines Interceptors, wie unten beschrieben.
Führen Sie hier den funktionierenden Demo-Plunker aus .
Erweiterte Verwendung: Abfangen aller Anforderungen oder Antworten
Der Angular.io-Leitfaden zeigt einmal mehr:
Ein Hauptmerkmal von @angular/common/http
ist das Abfangen, die Fähigkeit, Abfangjäger zu deklarieren, die zwischen Ihrer Anwendung und dem Backend liegen. Wenn Ihre Anwendung eine Anforderung stellt, transformieren Interceptors diese, bevor sie an den Server gesendet werden, und die Interceptors können die Antwort auf dem Rückweg transformieren, bevor Ihre Anwendung sie sieht. Dies ist nützlich für alles von der Authentifizierung bis zur Protokollierung.
Was natürlich verwendet werden kann, um Fehler auf sehr einfache Weise zu behandeln ( Demo-Plunker hier ):
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>>();
});
}
}
Bereitstellung Ihres Abfangjägers: Wenn Sie nur das HttpErrorInterceptor
oben Gesagte deklarieren, wird es von Ihrer App nicht verwendet. Sie müssen es in Ihrem App-Modul verkabeln, indem Sie es wie folgt als Interceptor bereitstellen:
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 {}
Hinweis: Wenn Sie sowohl einen Fehlerabfangjäger als auch eine lokale Fehlerbehandlung haben, wird natürlich wahrscheinlich nie eine lokale Fehlerbehandlung ausgelöst, da der Fehler immer vom Abfangjäger behandelt wird, bevor er die lokale Fehlerbehandlung erreicht.
Führen Sie hier den funktionierenden Demo-Plunker aus .
return this.httpClient.get<type>(...)
. und danncatch...
irgendwo außerhalb des Dienstes haben, wo er es tatsächlich konsumiert, weil er dort Observables Flow aufbauen wird und am besten damit umgehen kann.