2014-08-28 18 views
9

मैं सत्र-आधारित सेवाओं को कार्यान्वित कर रहा हूं। सभी अनुरोधों को एक कुकी सत्र परम के साथ सब्सक्राइब किया जाना चाहिए, जो बदले में अलग आराम एपीआई के साथ पुनर्प्राप्त किया जाता है। तो मूल वर्कफ़्लो सत्र कुकी प्राप्त करना और सेवाओं से पूछताछ करना होगा। कभी-कभी कुकी समाप्त हो जाती है और इससे दूसरे सत्र कुकी अनुरोध का कारण बन जाएगा।रेट्रोफिट/आरएक्सजेवा और सत्र-आधारित सेवाएं

मैं क्लाइंट कोड सत्र-अज्ञेयवादी बनाने की कोशिश कर रहा हूं, ताकि सत्र को बनाए रखने के बारे में चिंता न करें, बल्कि मैं इसे सेवा परत के अंदर छिपाना चाहता हूं।

क्या आप Retrofit/RxJava के साथ इसे लागू करने के विचार सुझा सकते हैं? मुझे लगता है कि SessionService, अन्य सभी सेवाओं से संक्षिप्त करने में इतना है कि वे यह क्वेरी कर सकता है जब भी यह आवश्यक है है, लेकिन मैं कैसे साथ यह करने के लिए यकीन नहीं है रेट्रोफिट के RestAdapter.create

उत्तर

25

मैं इस के समान कुछ किया है से पहले, लेकिन OAuth प्राधिकरण के साथ। असल में, आपके पास एक RestAdapter प्रारंभिक इंटरसेप्टर के साथ प्रारंभ किया गया है जो सत्र अनुरोध को प्रत्येक अनुरोध में जोड़ता है। किसी भी सत्र में अधिकृत होने पर RequestInterceptor को एक नया सत्र कुकी मिलती है।

निम्नलिखित रेट्रोफिट बाकी इंटरफ़ेस परिभाषा नीचे दिए गए उदाहरण कोड में प्रयोग किया जाता है:

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

अनुरोध इंटरसेप्टर प्रत्येक बाकी अनुरोध पर एक नज़र हो जाता है और हेडर, क्वेरी पैरामीटर जोड़ सकते हैं या URL को संशोधित कर सकते हैं। यह उदाहरण मानता है कि कुकी को HTTP शीर्षलेख के रूप में जोड़ा जाता है।

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

यह वह सत्र सेवा है जिसे आपने बताया है। यह जिम्मेदारी है कि नेटवर्क अनुरोध करना जो सत्र कुकी को अधिकृत/रीफ्रेश करता है।

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 वर्ग रेट्रोफिट इंटरफ़ेस लपेटता ताकि अनुरोध पुन: प्रयास करें तर्क प्रत्येक रेट्रोफिट प्रत्यक्ष करने के लिए जोड़ा जा सकता है।

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

पुन: प्रयास करें तर्क नीचे सत्र कुकी अद्यतन करने के लिए और अगर सत्र सर्वर के लिए भेजा कुकी एक HTTP अनधिकृत (401) त्रुटि देता है तो विफल रहा है बाकी अनुरोध पुन: प्रयास SessionService का प्रयोग करेंगे।

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

ग्राहक प्रवर्तन कोड कुछ ऐसा दिखाई देगा:

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

फिर एक बाकी RestService से नमूदार हो और नेटवर्क अनुरोध शुरू करने के लिए यह करने के लिए सदस्यता लें।

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

यह वास्तव में बहुत साफ दिखता है। धन्यवाद! – midnight

+0

त्रुटि: असंगत प्रकार: RetryWithSessionRefresh Func1 में परिवर्तित नहीं किया जा सकता ,? अवलोकन > यह वास्तव में केवल नेटफ्लिक्स – desgraci

+0

@desgraci से RxJava के विचलन के साथ काम करता है RryJava 1.0 में retryWhen() API बदल दिया गया था। मैंने 1.0+ संगतता के लिए उत्तर अपडेट किया है। – kjones

संबंधित मुद्दे