Tienes algunas opciones, según tus necesidades. Si desea manejar los errores por solicitud, agregue a catch
a su solicitud. Si desea agregar una solución global, use HttpInterceptor
.
Abra aquí el plunker de demostración en funcionamiento para las siguientes soluciones.
tl; dr
En el caso más simple, solo necesitará agregar una .catch()
o una .subscribe()
, como:
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)
);
Pero hay más detalles sobre esto, ver más abajo.
Solución de método (local): error de registro y respuesta de retorno de retorno
Si necesita manejar errores en un solo lugar, puede usar catch
y devolver un valor predeterminado (o una respuesta vacía) en lugar de fallar por completo. Tampoco necesitas .map
solo para emitir, puedes usar una función genérica. Fuente: Angular.io - Obteniendo detalles del error .
Entonces, un .get()
método genérico sería como:
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>();
});
}
}
Manejar el error permitirá que la aplicación continúe incluso cuando el servicio en la URL esté en malas condiciones.
Esta solución por solicitud es buena principalmente cuando desea devolver una respuesta predeterminada específica para cada método. Pero si solo le importa la visualización de errores (o tiene una respuesta predeterminada global), la mejor solución es usar un interceptor, como se describe a continuación.
Ejecute el plunker de demostración en funcionamiento aquí .
Uso avanzado: interceptar todas las solicitudes o respuestas
Una vez más, la guía Angular.io muestra:
Una característica importante de @angular/common/http
es la interceptación, la capacidad de declarar interceptores que se encuentran entre su aplicación y el backend. Cuando su aplicación realiza una solicitud, los interceptores la transforman antes de enviarla al servidor, y los interceptores pueden transformar la respuesta en su camino de regreso antes de que su aplicación la vea. Esto es útil para todo, desde la autenticación hasta el registro.
Que, por supuesto, se puede usar para manejar errores de una manera muy simple ( demo plunker aquí ):
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>>();
});
}
}
Proporcionar su interceptor: simplemente declarar lo HttpErrorInterceptor
anterior no hace que su aplicación lo use. Debe conectarlo en el módulo de su aplicación proporcionándolo como un interceptor, de la siguiente manera:
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: Si tiene tanto un interceptor de errores como un manejo de errores local, naturalmente, es probable que nunca se active el manejo de errores local, ya que el interceptor siempre manejará el error antes de que llegue al manejo de errores local.
Ejecute el plunker de demostración en funcionamiento aquí .
return this.httpClient.get<type>(...)
. y luego tener uncatch...
lugar fuera del servicio donde realmente lo consume porque ahí es donde construirá el flujo observable y podrá manejarlo mejor.