2014-08-28 21 views
9

Oturum tabanlı hizmetler uygulamıyorum. Tüm isteklerin bir cookie session param ile abone olması gerekir, bu da sırayla ayrı dinlenme api ile alınır. Dolayısıyla temel iş akışı, oturum çerezini almak ve hizmetleri sorgulamaya devam etmek olacaktır. Bazen, çerezin süresi dolardı ve başka bir oturum çerezi isteğine yol açacaktı.Güçlendirme/Rxjava ve oturum tabanlı hizmetler

İstemci kodu oturum-agnostik yapmaya çalışıyorum, böylece oturumu sürdürme konusunda endişelenmenize gerek yok, bunun yerine hizmet katmanı içinde gizlenmesini istiyorum.

Retrofit/RxJava ile ilgili uygulama önerileriniz var mı? Ben SessionService gerekli olduğunu zaman bunu sorgulayabilir, böylece diğer tüm hizmetler tarafından kapsüllü zorundadır düşünüyorum ama bunu nasıl emin değilim Retrofitler en RestAdapter.create

cevap

25

Daha önce ama buna benzer bir şey yaptık OAuth yetkilendirmesiyle. Temel olarak, her istek için oturum çerezi ekleyen bir RequestInterceptor ile başlatılmış bir RestAdapter var. RequestInterceptor, oturumun yetkilendirildiği her zaman yeni bir oturum çerezi alır.

aşağıdaki Güçlendirme DİNLENME arabirim tanımı

aşağıdaki örnek kod kullanılır:

interface ApiService { 
    @GET("/examples/v1/example") 
    Observable<Example> getExample(); 
} 

ayrıntılı önleme her dinlenme isteği bir göz alır ve başlıkları, sorgu parametreleri ekleyebilir veya URL değiştirebilir. Bu örnek, çerezin HTTP başlığı olarak eklendiğini varsayar.

class CookieHeaderProvider implements RequestInterceptor { 
    private String sessionCookie = ""; 

    public CookieHeaderProvider() { 
    } 

    public void setSesstionCookie(String sessionCookie) { 
     this.sessionCookie = sessionCookie; 
    } 

    @Override 
    public void intercept(RequestFacade requestFacade) { 
     requestFacade.addHeader("Set-Cookie", sessionCookie); 
    } 
} 

Bu, ima ettiğiniz SessionService'dir. Bu sorumluluk, oturum çerezini yetkilendiren/yenileyen ağ isteğini yapmaktır. Bu istek yeniden deneme mantığı gözlemlenebilir her Retrofit eklenebilir böylece

class SessionService { 
    // Modify contructor params to pass in anything needed 
    // to get the session cookie. 
    SessionService(...) { 
    } 

    public Observable<String> observeSessionCookie(...) { 
     // Modify to return an Observable that when subscribed to 
     // will make the network request to get the session cookie. 
     return Observable.just("Fake Session Cookie"); 
    } 
} 

RestService sınıf Retrofitler arayüzü sarar.

class RestService { 
    private final apiService; 
    private final sessionSerivce; 
    private final cookieHeaderProvider; 

    RestService(ApiService apiService, 
       SessionService sessionSerivce, 
       CookieHeaderProvider cookieHeaderProvider) { 
     this.apiService = apiService; 
     this.sessionSerivce = sessionSerivce; 
     this.cookieHeaderProvider = cookieHeaderProvider; 
    } 

    Observable<Example> observeExamples() { 
     // Return a Retrofit Observable modified with 
     // session retry logic. 
     return 
      apiService 
       .observeExamples() 
       .retryWhen(new RetryWithSessionRefresh(sessionSerivce, cookieHeaderProvider)); 
    } 
} 

yeniden deneme mantığı aşağıda oturum çerezi güncelleme ve sunucuya gönderilen oturum tanımlama bir HTTP Yetkisiz (401) hata dönerse o zaman başarısız DİNLENME isteklerini yeniden denemek için SessionService kullanacaktır.

public class RetryWithSessionRefresh implements 
     Func1<Observable<? extends Throwable>, Observable<?>> { 

    private final SessionService sessionSerivce; 
    private final CookieHeaderProvider cookieHeaderProvider; 

    public RetryWithSessionRefresh(SessionService sessionSerivce, 
            CookieHeaderProvider cookieHeaderProvider) { 
     this.sessionSerivce = sessionSerivce; 
     this.cookieHeaderProvider = cookieHeaderProvider; 
    } 

    @Override 
    public Observable<?> call(Observable<? extends Throwable> attempts) { 
     return attempts 
       .flatMap(new Func1<Throwable, Observable<?>>() { 
        public int retryCount = 0; 

        @Override 
        public Observable<?> call(final Throwable throwable) { 
         // Modify retry conditions to suit your needs. The following 
         // will retry 1 time if the error returned was an 
         // HTTP Unauthoried (401) response. 
         retryCount++; 
         if (retryCount <= 1 && throwable instanceof RetrofitError) { 
          final RetrofitError retrofitError = (RetrofitError) throwable; 
          if (!retrofitError.isNetworkError() 
            && retrofitError.getResponse().getStatus() == HttpStatus.SC_UNAUTHORIZED) { 
           return sessionSerivce 
             .observeSessionCookie() 
             .doOnNext(new Action1<String>() { 
              @Override 
              public void call(String sessionCookie) { 
               // Update session cookie so that next 
               // retrofit request will use it. 
               cookieHeaderProvider.setSesstionCookie(sessionCookie); 
              } 
             }) 
             .doOnError(new Action1<Throwable>() { 
              @Override 
              public void call(Throwable throwable) { 
               // Clear session cookie on error. 
               cookieHeaderProvider.setSesstionCookie(""); 
              } 
             }); 
          } 
         } 
         // No more retries. Pass the original 
         // Retrofit error through. 
         return Observable.error(throwable); 
        } 
       }); 
    } 
} 

Müşteri başlatma kodu buna benzer görünecektir:

CookieHeaderProvider cookieHeaderProvider = new CookieHeaderProvider(); 
SessionService sessionSerivce = new SessionService(); 

ApiService apiService = 
    new RestAdapter.Builder() 
     .setEndpoint(...) 
     .setClient(...) 
     .setRequestInterceptor(cookieHeaderProvider) 
     .build() 
     .create(ApiService.class); 

RestService restService = 
    new RestService(apiService, sessionSerivce, cookieHeaderProvider); 

Sonra RestService gelen gözlemlenebilir bir dinlen ve ağ isteğini başlaması abone.

Observable<Example> exampleObservable = 
    restService 
     .observeExamples(); 

Subsctiption subscription = 
    exampleObservable 
     .subscribe(new Observer<Example>() { 
      void onNext(Example example) { 
       // Do stuff with example 
      } 
      void onCompleted() { 
       // All done. 
      } 
      void onError(Throwalbe e) { 
       // All API errors will end up here. 
      } 
     }); 
+0

Aslında oldukça düzgün görünüyor. Teşekkürler! – midnight

+0

hatası: uyumsuz türler: RetryWithSessionRefresh Func1 ,? Gözlemlenebilir > aslında yalnızca RxJava'nın subflix – desgraci

+0

@desgraci'den dönüştürülmesiyle çalışır. RetryWhen() API'si, RxJava 1.0'da değiştirildi. 1.0+ uyumluluk için cevabı güncelledim. – kjones