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 onNexti 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ż Responsedzię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 HttpExceptioni wysłane na adres onError. Co też ma sens, ponieważ bez Responseopakowania, 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...