2015-11-18 7 views
61

Ich versuche, auf Retrofit 2.0 zu aktualisieren und RxJava in meinem Android-Projekt hinzuzufügen. Ich mache einen API-Anruf und möchte den Fehlercode im Falle einer Fehlerantwort vom Server abrufen.Erhalten Antwortstatuscode mit Retrofit 2.0 und RxJava

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, noch die RetrofitError bestanden und wir konnten den Status, indem Sie erhalten:

error.getResponse().getStatus() 

Wie Sie dies tun, mit Retrofit 2.0 mit RxJava?

Antwort

122

Statt den API-Aufruf zu erklären wie Sie haben:

Observable<MyResponseObject> apiCall(@Body body); 

Sie können auch es wie folgt erklären:

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

Sie haben dann einen Abonnenten wie folgt aus:

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

So werden Serverantworten mit einem Fehlercode auch an onNext geliefert und Sie können erhalten der Code durch den Aufruf reponse.code().

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

EDIT: OK, ich habe endlich um zu schauen, in welche E-nouri sagte in ihrem Kommentar, nämlich dass nur Codes 2xx zu onNext zu werden. Es stellte sich heraus, dass wir beide recht:

Wenn der Aufruf wie folgt erklärt:

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

oder diese sogar

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

alle Antworten in onNext, unabhängig von ihrem Fehler am Ende wird Code. Dies ist möglich, weil alles in einem Response Objekt von Retrofit verpackt ist.

Wenn auf der anderen Seite, wird der Anruf wie folgt erklärt:

Observable<MyResponseObject> apiCall(@Body body); 

oder diese

Observable<ResponseBody> apiCall(@Body body); 

in der Tat nur die 2xx Antworten auf onNext gehen. Alles andere wird in eine HttpException verpackt und an onError gesendet. Was macht auch Sinn, denn ohne Response wrapper was sollte an onNext ausgegeben werden? Angesichts der Tatsache, dass die Anfrage nicht erfolgreich war, wäre die einzige vernünftige Emission null ...

+9

Für Leute, die nach den HTTP-Codes 4xx suchen, enden sie als HttpException in onError. Das onNext wird nur das 2xx haben. –

+2

Das ist interessant ... Ich habe es nochmal überprüft (https://gist.github.com/DavidMihola/17a6ea373b9312fb723b) und alle Codes, die ich probiert habe, enden in 'onNext' inklusive 404 usw. Ich habe Retrofit v2.0.0-beta3 benutzt . –

+0

@ e-nouri: Ich habe meiner Antwort nur einen Absatz hinzugefügt, der Ihren Kommentar berücksichtigt! –

54

Innen onError Methode, um diese den Code erhalten setzen

((HttpException) e).code() 
+4

Das 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 mit der Antwort mit 'HttpException' machen müssen. Ich benutze RxJava und ich musste die Antwort analysieren, nachdem ich eine HTTP 400 BAD REQUEST erhalten habe. Vielen Dank! – GabrielOshiro

+13

Stellen Sie sicher, dass es zuvor eine Instanz von HttpException ist, da NetworkErrors IOExceptions sein und keinen Statuscode haben. –

+0

Um zu folgen von @BenjaminMesing sagte über NetworkError, wenn Sie mehr Downstream-Operatoren (map/flatMap/forEach etc ..) in Ihrem Rx vor dem Abonnieren tun, dann könnte es eine Vielzahl von möglichen Ausnahmearten, und nicht unbedingt ein Fehler auf der Netzwerkanforderung. –

1

Sie sollten beachten, dass, wie von Retrofit2 alle Antworten mit Code 2xx wird von OnNext() Callback und der Rest von aufgerufen werden HTTP Codes wie 4xx, 5xx wird auf der onError() Rückruf aufgerufen werden, Kotlin ich mit mit so etwas wie dies in der onError kam haben():

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