Zamiast deklarować wywołanie API, tak jak to zrobiłeś:
Observable<MyResponseObject> apiCall(@Body body);
Możesz również zadeklarować to w ten sposób:
Observable<Response<MyResponseObject>> apiCall(@Body body);
Będziesz mieć subskrybenta, takiego jak następujący:
new Subscriber<Response<StartupResponse>>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {
Timber.e(e, "onError: %", e.toString());
// network errors, e. g. UnknownHostException, will end up here
}
@Override
public void onNext(Response<StartupResponse> startupResponseResponse) {
Timber.d("onNext: %s", startupResponseResponse.code());
// HTTP errors, e. g. 404, will end up here!
}
}
Tak więc odpowiedzi serwera z kodem błędu również zostaną dostarczone do onNext
i możesz uzyskać kod, dzwoniąc reponse.code()
.
http://square.github.io/retrofit/2.x/retrofit/retrofit/Response.html
EDYCJA: OK, w końcu zajrzałem do tego, co powiedział e-nouri w swoim komentarzu, a mianowicie, że tylko kody 2xx będą onNext
. Okazuje się, że oboje mamy rację:
Jeśli wywołanie jest zadeklarowane w następujący sposób:
Observable<Response<MyResponseObject>> apiCall(@Body body);
a nawet to
Observable<Response<ResponseBody>> apiCall(@Body body);
wszystkie odpowiedzi zakończą się onNext
, niezależnie od kodu błędu. Jest to możliwe, ponieważ Response
dzięki Retrofitowi wszystko jest opakowane w obiekt.
Jeśli, z drugiej strony, wezwanie zostanie zadeklarowane w następujący sposób:
Observable<MyResponseObject> apiCall(@Body body);
albo to
Observable<ResponseBody> apiCall(@Body body);
w rzeczywistości tylko odpowiedzi 2xx trafią do onNext
. Wszystko inne zostanie zapakowane HttpException
i wysłane na adres onError
. Co też ma sens, ponieważ bez Response
opakowania, do czego powinno być emitowane onNext
? Biorąc pod uwagę, że żądanie się nie powiodło, jedyną rozsądną rzeczą do wyemitowania byłoby null
...