Obtener el código de estado de la respuesta utilizando Retrofit 2.0 y RxJava


Estoy tratando de actualizar a Retrofit 2.0 y agregar RxJava en mi proyecto de Android. Estoy haciendo una llamada a la api y quiero recuperar el código de error en caso de una respuesta de error del servidor.

Observable<MyResponseObject> apiCall(@Body body);

Y en la llamada RxJava:

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

En Retrofit 1.9, el RetrofitError todavía existía y podíamos obtener el estado haciendo:

error.getResponse().getStatus()

¿Cómo se hace esto con Retrofit 2.0 usando RxJava?

Author: ArtKorchagin, 2015-11-18

3 answers

En lugar de declarar la llamada a la API como lo hiciste:

Observable<MyResponseObject> apiCall(@Body body);

También puedes declararlo así: {[19]]}

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

Entonces tendrá un Suscriptor como el siguiente:

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

Por lo tanto, las respuestas del servidor con un código de error también se entregarán a onNext y puede obtener el código llamando a reponse.code().

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

EDITAR: OK, finalmente me puse a buscar en lo que e-nouri dicho en su comentario, a saber, que solo los códigos 2xx voluntad a a onNext. Resulta que ambos tenemos razón:

Si la llamada se declara así:

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

O incluso esto

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

Todas las respuestas terminarán en onNext, independientemente de su código de error. Esto es posible porque todo está envuelto en un objeto Response por Retrofit.

Si, por otro lado, la llamada se declara así: {[19]]}

Observable<MyResponseObject> apiCall(@Body body);

O esto

Observable<ResponseBody> apiCall(@Body body);

De hecho solo el 2xx las respuestas irán a onNext. Todo lo demás será envuelto en un HttpException y enviado a onError. Lo que también tiene sentido, porque sin la envoltura Response, ¿qué debería emitirse a onNext? Dado que la solicitud no tuvo éxito, lo único sensato para emitir sería null...

 148
Author: david.mihola,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-31 18:07:01

Dentro del método onError poner a esto obtener el código

((HttpException) e).code()
 63
Author: Diveno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-17 07:27:55

Debes tener en cuenta que a partir de Retrofit2 todas las respuestas con código 2xx se llamarán desde onNext () callback y el resto de códigos HTTP como 4xx, 5xx se llamarán en el onError () callback, usando Kotlin Se me ocurrió algo como esto en el unError() :

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))
  }
 3
Author: MohammadReza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-23 06:36:26