web-dev-qa-db-fra.com

Obtenir le code d'état de la réponse à l'aide de Retrofit 2.0 et de RxJava

J'essaie de passer à Retrofit 2.0 et d'ajouter RxJava à mon projet Android. Je passe un appel à l'API et souhaite récupérer le code d'erreur en cas de réponse d'erreur du serveur.

Observable<MyResponseObject> apiCall(@Body body);

Et dans l'appel 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
        }
    });

Dans Retrofit 1.9, RetrofitError existait toujours et nous pouvions obtenir le statut en procédant comme suit:

error.getResponse().getStatus()

Comment faites-vous cela avec Retrofit 2.0 en utilisant RxJava?

98
A.B.

Au lieu de déclarer l'appel API comme vous l'avez fait:

Observable<MyResponseObject> apiCall(@Body body);

Vous pouvez aussi le déclarer comme ceci:

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

Vous aurez alors un abonné comme celui-ci:

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

Ainsi, les réponses du serveur avec un code d'erreur seront également envoyées à onNext et vous pourrez obtenir le code en appelant reponse.code().

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

EDIT: OK, je me suis enfin mis à chercher dans ce que e-nouri avait dit dans son commentaire, à savoir que seuls les codes 2xx permettraient de onNext. Il s'avère que nous avons tous les deux raison:

Si l'appel est déclaré comme ceci:

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

ou même cela

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

toutes les réponses se retrouveront dans onNext, quel que soit leur code d'erreur. Ceci est possible car tout est encapsulé dans un objet Response par Retrofit.

Si, au contraire, l'appel est déclaré comme ceci:

Observable<MyResponseObject> apiCall(@Body body);

ou ca

Observable<ResponseBody> apiCall(@Body body);

en effet, seules les réponses 2xx iront à onNext. Tout le reste sera enveloppé dans un HttpException et envoyé à onError. Ce qui a également un sens, car sans le wrapper Response, que devrait être émis vers onNext? Étant donné que la demande n'a pas abouti, la seule chose sensée à émettre serait null...

175
david.mihola

La méthode interne onError mise à cela obtenir le code

((HttpException) e).code()
97
Diveno

Notez que, à compter de Retrofit2, toutes les réponses avec le code 2xx seront appelées à partir du rappel onNext () et le reste de codes HTTP comme 4xx, 5xx sera appelé sur le rappel onError (), en utilisant Kotlin J'ai créé quelque chose comme ceci dans le 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))
  }
7
MohammadReza