2017-01-15 3 views
1

J'envoie une requête de connexion au serveur avec retrofit 2.0, et le serveur retourne au jeton de session client, que je dois utiliser dans d'autres requêtes, mais ce jeton a une durée de vie limitée et quand il est expire serveur renvoie une erreur HTTP 401.Comment changer les paramètres dans une nouvelle tentative après une erreur dans RxJava

J'essaie faire re-ouverture de session, après avoir obtenu cette erreur, avec l'aide d'un code suivant:

holder.getApi(GuideProfileApi.class) 
     .getProfile(String.valueOf(holder.getServerId()), holder.getServerToken()) 
     .subscribeOn(Schedulers.io()) 
     .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() { 
     @Override 
     public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception { 
      return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() { 
      @Override 
      public ObservableSource<?> apply(Throwable throwable) throws Exception { 
       if (throwable instanceof HttpException && ((HttpException)throwable).code() == 401) { 
       RegistryLoginResult loginResult = holder.login().blockingSingle(); 
       return holder.getApi(GuideProfileApi.class) 
        .getProfile(String.valueOf(loginResult.getUserId()), loginResult.getSessionToken()); 
       } 
       return Observable.error(throwable); 
      } 
     }); 
    } 
    }) 
    .observeOn(AndroidSchedulers.mainThread()) 
    .subscribe(new Consumer<ProfileResult>() { 
    @Override 
    public void accept(ProfileResult profileResult) throws Exception { 
     Log.d("Result", profileResult.toString()); 
    } 
    }, new Consumer<Throwable>() { 
     @Override 
     public void accept(Throwable throwable) throws Exception { 
     Log.e("Result", throwable.getLocalizedMessage()); 
     } 
}); 

et nouvelle tentative demande est envoyée, mais les paramètres de demande est la même que dans une demande incorrecte (avant de se reconnecter). Comment puis-je changer les paramètres de la requête avant de l'envoyer à nouveau?

Répondre

1

Vous utilisez le mauvais opérateur. retryWhen va réessayer votre original observable s'il rencontre une erreur. Ce dont vous avez besoin est onErrorResumeNext. Quelque chose comme

holder.getApi(GuideProfileApi.class) 
     .getProfile(String.valueOf(holder.getServerId()), holder.getServerToken()) 
     .subscribeOn(Schedulers.io()) 
     .onErrorResumeNext(new Function<Throwable, ObservableSource<?>>() { 
     @Override 
     public ObservableSource<?> apply(Throwable throwable) { 
       if (throwable instanceof HttpException && ((HttpException)throwable).code() == 401) { 
       RegistryLoginResult loginResult = holder.login().blockingSingle(); 
       return holder.getApi(GuideProfileApi.class) 
        .getProfile(String.valueOf(loginResult.getUserId()), loginResult.getSessionToken()); 
       } 
       return Observable.error(throwable); 
     } 
    }) 
    .observeOn(AndroidSchedulers.mainThread()) 
    .subscribe(new Consumer<ProfileResult>() { 
    @Override 
    public void accept(ProfileResult profileResult) throws Exception { 
     Log.d("Result", profileResult.toString()); 
    } 
    }, new Consumer<Throwable>() { 
     @Override 
     public void accept(Throwable throwable) throws Exception { 
     Log.e("Result", throwable.getLocalizedMessage()); 
     } 
}); 
+0

Il fonctionne, mais comment je peux changer originar observable? – Pavel

+0

Comment exclure 'return holder.getApi (GuideProfileApi.class) .getProfile (String.valueOf (loginResult.getUserId()), loginResult.getSessionToken());' et modifier les paramètres de l '** original observable **? – Pavel

+0

Je crois que les observables dans rxjava sont immuables. Une fois que vous avez créé un observable, vous ne pouvez pas revenir en arrière et le changer. – JohnWowUs

4

Vous pouvez utiliser retryWhen, mais le problème est que votre nouvelle tentative retryWhen le même objet observable que vous créez dans un moment paresseux. Votre solution ici est d'utiliser l'opérateur defer pour obtenir l'hôte(), puisque différer ne crée pas l'observable quand vous le définissez mais quand il est consommé par l'abonné.

Observable.defer(()-> holder.getApi(GuideProfileApi.class) 
      .getProfile(String.valueOf(holder.getServerId()),holder.getServerToken())) 
    .subscribeOn(Schedulers.io()) 
    .retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() { 
    @Override 
    public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception { 
     return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() { 
     @Override 
     public ObservableSource<?> apply(Throwable throwable) throws Exception { 
      if (throwable instanceof HttpException && ((HttpException)throwable).code() == 401) { 
      RegistryLoginResult loginResult = holder.login().blockingSingle(); 
      return holder.getApi(GuideProfileApi.class) 
       .getProfile(String.valueOf(loginResult.getUserId()), loginResult.getSessionToken()); 
      } 
      return Observable.error(throwable); 
     } 
    }); 
} 
    }) 
    .observeOn(AndroidSchedulers.mainThread()) 
    .subscribe(new Consumer<ProfileResult>() { 
    @Override 
    public void accept(ProfileResult profileResult) throws Exception { 
     Log.d("Result", profileResult.toString()); 
    } 
     }, new Consumer<Throwable>() { 
      @Override 
      public void accept(Throwable throwable) throws Exception { 
      Log.e("Result", throwable.getLocalizedMessage()); 
      } 
    }); 

Vous pouvez voir quelques exemples de nouvelles tentatives ici https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/errors/ObservableExceptions.java

+0

merci, cela fonctionne –