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 catch
e retornar um valor padrão (ou resposta vazia) em vez de falhar completamente. Você também não precisa do .map
apenas 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 HttpErrorInterceptor
acima 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.