Erhalten Sie den Antwortstatuscode mit Retrofit 2.0 und RxJava

107

Ich versuche, auf Retrofit 2.0 zu aktualisieren und RxJava in mein Android-Projekt aufzunehmen. Ich mache einen API-Aufruf und möchte den Fehlercode im Falle einer Fehlerantwort vom Server abrufen.

Observable<MyResponseObject> apiCall(@Body body);

Und im RxJava-Aufruf:

myRetrofitObject.apiCall(body).subscribe(new Subscriber<MyResponseObject>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(MyResponseObject myResponseObject) {
           //On response from server
        }
    });

In Retrofit 1.9 war der RetrofitError noch vorhanden, und wir konnten den Status wie folgt abrufen:

error.getResponse().getStatus()

Wie geht das mit Retrofit 2.0 mit RxJava?

AB
quelle

Antworten:

185

Anstatt den API-Aufruf wie folgt zu deklarieren:

Observable<MyResponseObject> apiCall(@Body body);

Sie können es auch so deklarieren:

Observable<Response<MyResponseObject>> apiCall(@Body body);

Sie haben dann einen Abonnenten wie den folgenden:

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!
    }
}

Serverantworten mit einem Fehlercode werden also auch an gesendet, onNextund Sie können den Code durch Aufrufen abrufen reponse.code().

http://square.github.io/retrofit/2.x/retrofit/retrofit/Response.html

EDIT: OK, ich habe mich endlich damit beschäftigt, zu untersuchen, was e-nouri in ihrem Kommentar gesagt hat, nämlich dass nur 2xx Codes dazu gehören onNext. Es stellt sich heraus, dass wir beide Recht haben:

Wenn der Anruf wie folgt deklariert ist:

Observable<Response<MyResponseObject>> apiCall(@Body body);

oder sogar das

Observable<Response<ResponseBody>> apiCall(@Body body);

Alle Antworten werden onNextunabhängig von ihrem Fehlercode angezeigt. Dies ist möglich, weil alles Responsevon Retrofit in ein Objekt eingewickelt wird.

Wenn andererseits der Anruf wie folgt deklariert wird:

Observable<MyResponseObject> apiCall(@Body body);

oder dieses

Observable<ResponseBody> apiCall(@Body body);

in der Tat werden nur die 2xx Antworten gehen onNext. Alles andere wird in ein verpackt HttpExceptionund an gesendet onError. Was macht auch Sinn, denn Responsewas soll ohne Wrapper ausgegeben werden onNext? Da die Anfrage nicht erfolgreich war, wäre es nur sinnvoll, null...

david.mihola
quelle
16
Personen, die nach den HTTP-Codes 4xx suchen, werden als HttpException in onError angezeigt. Der onNext hat nur den 2xx.
E-Nouri
2
Das ist interessant ... Ich habe es gerade noch einmal überprüft ( gist.github.com/DavidMihola/17a6ea373b9312fb723b ) und alle Codes, die ich ausprobiert habe, enthalten onNext404 usw. Ich habe Retrofit v2.0.0-beta3 verwendet.
David.mihola
@ e-nouri: Ich habe meiner Antwort gerade einen Absatz hinzugefügt, der Ihren Kommentar berücksichtigt!
David.mihola
1
@ david.mihola Wenn Build Retrofit über add GsonConverterFactory, genauso wie Retrofit retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create())Wie bekomme ich die ursprüngliche Antwort?
Honghe.Wu
1
Abgesehen von der Fehlerbehandlung möchten Sie möglicherweise alle Antwort-Header überprüfen, die mit dem Body geliefert wurden - dies ist auch nur möglich, wenn Sie die erhalten Response. Ich benutze es auch selten - aber ich finde es gut zu wissen, dass es existiert.
David.mihola
112

Innerhalb der onError-Methode setzen Sie dies, um den Code zu erhalten

((HttpException) e).code()
Diveno
quelle
7
Dies könnte eine der am meisten unterschätzten Antworten sein, die ich je in SO gesehen habe. Das ist Genie. Sie können alles tun, was Sie für die Antwort benötigen HttpException. Ich verwende RxJava und musste die Antwort nach Erhalt von a analysieren HTTP 400 BAD REQUEST. Vielen Dank!
GabrielOshiro
29
Stellen Sie einfach sicher, dass Sie vorher prüfen, ob es sich um eine Instanz von HttpException handelt, da NetworkErrors IOExceptions sind und keinen Statuscode haben.
Benjamin Mesing
Um @BenjaminMesing zu folgen, sagte NetworkError: Wenn Sie mehr Downstream-Operatoren (map / flatMap / forEach usw.) in Ihrem Rx ausführen, bevor Sie sich anmelden, kann es eine Vielzahl möglicher Ausnahmetypen geben, und nicht unbedingt einen Fehler die Netzwerkanforderung.
Mark Keen
java.lang.ClassCastException: java.lang.Throwable kann nicht in retrofit2.HttpException umgewandelt werden
Jemand irgendwo
7

Sie sollten beachten , dass ab Retrofit2 alle Antworten mit Code 2xx aus OnNext () Rückruf und den Rest genannt werden HTTP - Codes wie 4xx, 5xx auf dem heißen wird onError () Rückruf, mit Kotlin Ich habe kam mit so etwas wie dies im onError () :

mViewReference?.get()?.onMediaFetchFinished(downloadArg)
  if (it is HttpException) {
    val errorCode = it.code()
    mViewReference?.get()?.onMediaFetchFailed(downloadArg,when(errorCode){
      HttpURLConnection.HTTP_NOT_FOUND -> R.string.check_is_private
      else -> ErrorHandler.parseError(it)
    })
  } else {
    mViewReference?.get()?.onMediaFetchFailed(downloadArg, ErrorHandler.parseError(it))
  }
MohammadReza
quelle