Retrofit + RxJava no puede almacenar en caché las respuestas, los encabezados de respuesta sospechados

Estoy tratando de configurar caché con Retrofit 1.9.0 y OkHtttp 2.5.0 .

Aquí es cómo OkHttpClient para mi 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; } 

No me olvidé de setClient en RestAdapter.Builder . También se aseguró de que en realidad estoy usando la instancia de RestAdapter con este conjunto de clientes.

Incluso comprobado si los archivos se crean en la carpeta "http". Son.

Sin embargo después de que me doy vuelta de WIFI y recargue mi pantalla termino para arriba en OnError callback del extremo Observable con este mensaje:

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

EXENCIÓN DE RESPONSABILIDAD: Debo mencionar que el Observable final se combina de otros 5, con flatMap y zip en el camino.

Creo que tengo una respuesta. Un corto es: "No se puede hacer si el servidor envía el encabezado de no-cache en respuesta".

Si desea la más larga, los detalles están a continuación.

He hecho una aplicación de ejemplo comparando 2 backends. Vamos a llamar a Backend A, y Backend B. A me estaba dando problemas, así que he decidido comprobar en B.

A devuelve CacheControl = "no-cache, no-transform, max-age=0"

B devuelve Cache-Control = „public" encabezado de respuesta Cache-Control = „public"

Hice la misma configuración para ambos backends, sólo diferentes urls.

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

Hicimos las dos llamadas, entonces wifi discapacitados. Cache funcionó bien para B, pero A lanzado 504 Unsatisfiable Request (only-if-cached)

Parece que sobrescribir encabezados no ayudará en ese caso.

Deberá volver a escribir su Request lugar de la Response . Para referencia, vea los documentos sobre las solicitudes de reescritura . Tenga en cuenta que, también puede utilizar la clase CacheControl lugar de construir su propia cabecera si lo desea. Su interceptor debe ser algo como –

 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); } }); 
  • Obtenga el valor actual de RxJava Observable
  • RxJava solo planificador de hilos de fondo
  • RxJava filtro 'else'
  • AbstractMethodError cuando se utiliza RxJavaCallAdapterFactory en Retrofit 2
  • RxJava con presentador y fragmento retenido para cambios de configuración
  • ¿Asignación de objetos cuando se usa RxJava en código de 'alto tráfico'?
  • La llamada a la API de Retrofit recibe "HTTP FAILED: java.io.IOException: Cancelled"
  • RxJava + Retrofit + sondeo
  • RxJava / RxAndroid - maneja varios cambios de EditText
  • ¿Cómo puedo hacer que este zip rxjava funcione en paralelo?
  • Cómo obtener un Desechable para sujetos como suscriptor en RxJava2
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.