Masz kilka opcji, w zależności od potrzeb. Jeśli chcesz obsługiwać błędy na podstawie poszczególnych żądań, dodaj catch
do żądania. Jeśli chcesz dodać globalne rozwiązanie, użyj HttpInterceptor
.
Otwórz tutaj działający plunker demonstracyjny dla poniższych rozwiązań.
tl; dr
W najprostszym przypadku wystarczy dodać a .catch()
lub a .subscribe()
, na przykład:
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)
);
Ale jest więcej szczegółów na ten temat, patrz poniżej.
Rozwiązanie metody (lokalne): błąd dziennika i zwrot odpowiedzi rezerwowej
Jeśli potrzebujesz obsługiwać błędy tylko w jednym miejscu, możesz użyć catch
i zwrócić wartość domyślną (lub pustą odpowiedź) zamiast całkowicie zawieść. Nie potrzebujesz też .map
tylko do rzutowania, możesz użyć funkcji ogólnej. Źródło: Angular.io - Pobieranie szczegółów błędu .
Tak więc ogólna .get()
metoda wyglądałaby tak:
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>();
});
}
}
Obsługa błędu umożliwi kontynuowanie działania aplikacji nawet wtedy, gdy usługa pod adresem URL jest w złym stanie.
To rozwiązanie na żądanie jest dobre głównie wtedy, gdy chcesz zwrócić określoną domyślną odpowiedź dla każdej metody. Ale jeśli zależy Ci tylko na wyświetlaniu błędów (lub masz globalną odpowiedź domyślną), lepszym rozwiązaniem jest użycie przechwytywacza, jak opisano poniżej.
Uruchom tutaj działającego demo plunkera .
Użycie zaawansowane: przechwytywanie wszystkich żądań lub odpowiedzi
Po raz kolejny przewodnik Angular.io pokazuje:
Główną cechą @angular/common/http
jest przechwytywanie, czyli możliwość deklarowania przechwytywaczy, które znajdują się pomiędzy aplikacją a zapleczem. Kiedy aplikacja wysyła żądanie, elementy przechwytujące przekształcają je przed wysłaniem do serwera, a przechwytywacze mogą przekształcić odpowiedź w drodze powrotnej, zanim aplikacja ją zobaczy. Jest to przydatne do wszystkiego, od uwierzytelniania po rejestrowanie.
Które oczywiście można wykorzystać do obsługi błędów w bardzo prosty sposób ( tutaj demo plunker ):
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>>();
});
}
}
Zapewnienie przechwytywacza: samo zadeklarowanie HttpErrorInterceptor
powyższego nie spowoduje, że aplikacja będzie go używać. Musisz połączyć go w module aplikacji, dostarczając go jako przechwytywacz w następujący sposób:
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 {}
Uwaga: Jeśli masz zarówno przechwytywacz błędów, jak i pewną lokalną obsługę błędów, jest oczywiście prawdopodobne, że żadna lokalna obsługa błędów nigdy nie zostanie wyzwolona, ponieważ błąd będzie zawsze obsługiwany przez przechwytywacz, zanim dotrze do lokalnej obsługi błędów.
Uruchom tutaj działającego demo plunkera .
return this.httpClient.get<type>(...)
. a potem miećcatch...
gdzieś poza usługą, gdzie faktycznie to konsumuje, ponieważ tam będzie budował przepływ obserwowalny i może sobie z tym najlepiej poradzić.Promise<Object>
klienta (wywołującegoDataService
metody) do obsługi błędu. Przykład:this.dataService.post('url', {...}).then(...).catch((e) => console.log('handle error here instead', e));
. Wybierz to, co jest bardziej zrozumiałe dla Ciebie i użytkowników Twojej usługi.return Observable.of({my: "default value..."});
generuje błąd „| ...” nie można przypisać do typu „HttpEvent <any>”. "HttpEvent
, na przykład aHttpResponse
. Tak więc, na przykład, można użyć:return Observable.of(new HttpResponse({body: [{name: "Default value..."}]}));
. Zaktualizowałem odpowiedź, aby wyjaśnić tę kwestię. Stworzyłem również działający demo plunker, aby pokazać wszystko działające: plnkr.co/edit/ulFGp4VMzrbaDJeGqc6q?p=previewProszę pozwolić mi zaktualizować odpowiedź acdcjunior dotyczącą używania HttpInterceptor z najnowszymi funkcjami RxJs (v.6).
źródło
Wraz z pojawieniem się
HTTPClient
API, nie tylko został wymienionyHttp
API, ale dodano nowy,HttpInterceptor
API.AFAIK jednym z jego celów jest dodanie domyślnego zachowania do wszystkich wychodzących żądań HTTP i odpowiedzi przychodzących.
Zakładając więc, że chcesz dodać domyślne zachowanie obsługi błędów , dodanie
.catch()
do wszystkich możliwych metod http.get / post / etc jest śmiesznie trudne w utrzymaniu.Można to zrobić w następujący sposób, na przykład, używając
HttpInterceptor
:// app.module.ts
Dodatkowe informacje dla OP: Wywołanie http.get / post / etc bez silnego typu nie jest optymalnym wykorzystaniem API. Twoja usługa powinna wyglądać następująco:
Powrót
Promises
z metod serwisu zamiast z nichObservables
to kolejna zła decyzja.I dodatkowa rada: jeśli używasz skryptu TYPE , zacznij używać jego części typu. Tracisz jedną z największych zalet języka: znać rodzaj wartości, z którą masz do czynienia.
Jeśli chcesz, moim zdaniem, dobry przykład usługi kątowej, spójrz na następującą istotę .
źródło
this.http.get()
itd., A niethis.get()
itd. WDataService
?Dość proste (w porównaniu z tym, jak zostało to zrobione z poprzednim API).
Źródło z (skopiuj i wklej) oficjalnego przewodnika Angular
źródło
W przypadku Angular 6+ .catch nie działa bezpośrednio z Observable. Musisz użyć
Poniżej kod:
Aby uzyskać więcej informacji, zapoznaj się z przewodnikiem Angular Guide for Http
źródło
Przykład usługi obsługi błędów HttpClient w Angular 8
api.service.ts
źródło
Prawdopodobnie chcesz mieć coś takiego:
W dużej mierze zależy to również od tego, jak korzystasz z usług, ale jest to podstawowy przypadek.
źródło
Po odpowiedzi @acdcjunior zaimplementowałem ją w ten sposób
usługa:
gość:
źródło
źródło
Jeśli nie możesz wychwycić błędów w żadnym z przedstawionych tutaj rozwiązań, może to oznaczać, że serwer nie obsługuje żądań CORS.
W takim przypadku Javascript, a tym bardziej Angular, może uzyskać dostęp do informacji o błędzie.
Poszukaj ostrzeżeń w konsoli, które obejmują
CORB
lubCross-Origin Read Blocking
.Zmieniła się również składnia obsługi błędów (jak opisano w każdej innej odpowiedzi). Teraz używasz operatorów z potokami, jak na przykład:
źródło
Używając Interceptora, możesz złapać błąd. Poniżej kod:
Możesz preferować tego bloga .. mając na to prosty przykład.
źródło