2015-09-16 16 views
10

Próbuję skonfigurować pamięć podręczną za pomocą Retrofit 1.9.0 i OkHtttp 2.5.0.Retrofit + RxJava nie buforuje odpowiedzi, podejrzane nagłówki odpowiedzi

Oto jak zapewnić OkHttpClient dla mojego RestAdapter:

@Provides 
@Singleton 
public OkHttpClient provideOkHttpClient() { 
    OkHttpClient okHttpClient = new OkHttpClient(); 
    okHttpClient.setConnectTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); 
    okHttpClient.setReadTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); 
    okHttpClient.setWriteTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); 

    File cacheDir = new File(context.getCacheDir(), "http"); 
    final Cache cache = new Cache(cacheDir, DISK_CACHE_SIZE_IN_BYTES); 
    okHttpClient.setCache(cache); 

    okHttpClient.interceptors().add(new Interceptor() { 
     @Override 
     public Response intercept(Chain chain) throws IOException { 

      Response response = chain.proceed(request); 
      Response finalResponse = response.newBuilder() 
        .header("Cache-Control", String.format("public, max-stale=%d", 604800)) 
        .build(); 

      Log.d("OkHttp", finalResponse.toString()); 
      Log.d("OkHttp Headers", finalResponse.headers().toString()); 
      return finalResponse; 
     } 
    }); 

    return okHttpClient; 
} 

Nie zapomnij setClient na RestAdapter.Builder. Upewniłem się również, że faktycznie używam instancji RestAdapter z tym zestawem klienta.

Sprawdzane nawet jeśli pliki są tworzone w folderze "http". Oni są.

Jednak po włączeniu z WIFI i odświeżyć mój ekran skończę w OnError zwrotnego z Observable końcowego z tej wiadomości:

retrofit.RetrofitError: failed to connect to /10.40.31.12 (port 8888) after 10000ms: connect failed: ENETUNREACH (Network is unreachable) 

ZASTRZEŻENIE: Powinienem chyba wspomnieć, że ostateczna Observable łączy się z 5 innymi z flatMap i zip w drodze.

+0

możliwy duplikat [Można dokonać modernizacji przy użyciu OKHttp użyj danych z pamięci podręcznej w trybie offline] (http://stackoverflow.com/questions/23429046/can-retrofit-with-okhttp-use-cache-data-when-offline) – njzk2

Odpowiedz

3

Myślę, że mam odpowiedź. Krótkie jest: "Nie można tego zrobić, jeśli serwer wyśle ​​w nagłówku brak bufora podręcznego".

Jeśli chcesz dłuższy, szczegóły są poniżej.

Zrobiłem przykładową aplikację porównującą 2 backendy. Nazwijmy je Backend A i B. Backend dawał mi kłopotów, więc postanowiliśmy sprawdzić B.

zwraca CacheControl = "no-cache, no-transform, max-age=0"

B zwraca nagłówku Cache-Control = „public" Response

zrobiłem taką samą konfigurację dla obu backendów, po prostu różne adresy URL.

private void buildApi() { 
     Gson gson = new GsonBuilder().create(); 

     OkHttpClient okHttpClient = new OkHttpClient(); 
     okHttpClient.setConnectTimeout(10, TimeUnit.SECONDS); 

     File cacheDir = new File(getCacheDir(), "http"); 
     final Cache cache = new Cache(cacheDir, 1000000 * 10); 
     okHttpClient.setCache(cache); 

     okHttpClient.interceptors().add(new Interceptor() { 
      @Override 
      public Response intercept(Chain chain) throws IOException { 
       Request request = chain.request(); 
       Log.d("OkHttp REQUEST", request.toString()); 
       Log.d("OkHttp REQUEST Headers", request.headers().toString()); 

       Response response = chain.proceed(request); 
       response = response.newBuilder() 
         .header("Cache-Control", String.format("public, max-age=%d, max-stale=%d", 60, RESPONSE_CACHE_LIFESPAN_IN_SECONDS)) 
         .build(); 

       Log.d("OkHttp RESPONSE", response.toString()); 
       Log.d("OkHttp RESPONSE Headers", response.headers().toString()); 
       return response; 
      } 
     }); 

     RestAdapter.Builder builder = new RestAdapter.Builder() 
       .setConverter(new StringGsonConverter(gson)) 
       .setClient(new OkClient(okHttpClient)) 
       .setRequestInterceptor(new RequestInterceptor() { 
        @Override 
        public void intercept(RequestFacade request) { 

         if (isNetworkAvailable()) { 
          request.addHeader("Cache-Control", "public, max-age=" + 60); 
         } else { 
          request.addHeader("Cache-Control", "public, only-if-cached, max-stale=" + RESPONSE_CACHE_LIFESPAN_IN_SECONDS); 
         } 
        } 
       }); 

     builder.setEndpoint("http://this.is.under.vpn.so.wont.work.anyway/api"); 
     A_API = builder.build().create(AApi.class); 

     builder.setEndpoint("http://collector-prod-server.elasticbeanstalk.com/api"); 
     B_API = builder.build().create(BApi.class); 
    } 

Wykonano obie rozmowy, a następnie wyłączono wifi. Pamięć podręczna działała poprawnie dla B, ale wyrzucono: 504 Unsatisfiable Request (only-if-cached)

Wygląda na to, że nadpisywanie nagłówków nie pomoże w tym przypadku.

2

Powinieneś przepisać swój Request zamiast Response. Aby uzyskać odniesienie, zobacz dokumentację na stronie rewriting requests. Zauważ, możesz też użyć klasy CacheControl zamiast budować swój własny nagłówek, jeśli chcesz. Twój przechwytnik powinien wyglądać mniej więcej -

okHttpClient.interceptors().add(new Interceptor() { 
    @Override 
    public Response intercept(Chain chain) throws IOException { 

    Request request = chain.request(); 
    Request cachedRequest = request.newBuilder() 
     .cacheControl(new CacheControl.Builder() 
      .maxStale(7, TimeUnit.DAYS) 
      .build()) 
     .build(); 

    return chain.proceed(cachedRequest); 
    } 
}); 
+0

Niestety to nie działa –

+0

Tak, to nie działa. – amj

Powiązane problemy