Você tem algumas opções, dependendo de suas necessidades. Se você quiser tratar os erros por solicitação, adicione um catchà sua solicitação. Se você quiser adicionar uma solução global, use HttpInterceptor.
Abra aqui o êmbolo de demonstração de trabalho para as soluções abaixo.
tl; dr
No caso mais simples, você só precisa adicionar um .catch()ou um .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)
);
Mas há mais detalhes sobre isso, veja abaixo.
Solução do método (local): registrar o erro e retornar a resposta de fallback
Se precisar lidar com erros em apenas um lugar, você pode usar catche retornar um valor padrão (ou resposta vazia) em vez de falhar completamente. Você também não precisa do .mapapenas para lançar, você pode usar uma função genérica. Fonte: Angular.io - Obtendo detalhes do erro .
Portanto, um .get()método genérico seria 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>();
});
}
}
Lidar com o erro permitirá que seu aplicativo continue, mesmo quando o serviço no URL estiver em más condições.
Essa solução por solicitação é boa principalmente quando você deseja retornar uma resposta padrão específica para cada método. Mas se você se preocupa apenas com a exibição de erros (ou tem uma resposta padrão global), a melhor solução é usar um interceptor, conforme descrito abaixo.
Execute o plunker de demonstração de trabalho aqui .
Uso avançado: interceptando todas as solicitações ou respostas
Mais uma vez, o guia Angular.io mostra:
Um dos principais recursos do @angular/common/httpé a interceptação, a capacidade de declarar interceptadores que ficam entre seu aplicativo e o back-end. Quando seu aplicativo faz uma solicitação, os interceptores a transformam antes de enviá-la ao servidor e podem transformar a resposta no caminho de volta antes que seu aplicativo a veja. Isso é útil para tudo, desde autenticação até registro.
Que, claro, pode ser usado para lidar com erros de uma forma muito simples ( plunker de demonstração aqui ):
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>>();
});
}
}
Fornecendo seu interceptor: simplesmente declarar o HttpErrorInterceptoracima não faz com que seu aplicativo o use. Você precisa conectá-lo ao seu módulo de app , fornecendo-o como um interceptor, da seguinte maneira:
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 você tem tanto um interceptor de erro e alguns manipulação de erro local, naturalmente, é provável que nenhum tratamento de erros local irá sempre ser acionado, desde que o erro será sempre tratado pelo interceptor antes que ele atinja o tratamento de erros local.
Execute o plunker de demonstração de trabalho aqui .
return this.httpClient.get<type>(...). e, em seguida, tercatch...algum lugar fora do serviço onde ele realmente consome, porque é onde ele estará construindo um fluxo observável e poderá lidar com isso melhor.