Дооснащение + RxJava не кэширует ответы, подозрительные заголовки ответов

Я пытаюсь настроить кеш с Retrofit 1.9.0 и OkHtttp 2.5.0.

Вот как я предоставляю OkHttpClient для моего 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;
}

Я не забыл setClient на RestAdapter.Builder. Также убедитесь, что я фактически использую экземпляр RestAdapter с этим набором клиентов.

Даже проверено, созданы ли файлы в папке "http". Они.

Однако после того, как я вернусь к WIFI и перезагрузите свой экран, я заканчиваю в OnError обратном вызове конечной точки Observable с этим сообщением:

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

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я должен, вероятно, упомянуть, что окончательный Observable объединяется с 5 другими, с flatMap и zip в пути.

Ответ 1

Думаю, у меня есть ответ. Коротким является: "Невозможно выполнить, если сервер отправляет заголовок без кэша в ответ".

Если вам нужен более длинный, детали ниже.

Я сделал пример приложения, сравнивающего 2 бэкэнда. Позволяет называть их Backend A и Backend B. A давал мне проблемы, поэтому я решил проверить B.

A возвращает CacheControl = "no-cache, no-transform, max-age=0"

B возвращает Cache-Control = „public" заголовок ответа

Я сделал ту же настройку для обоих бэкэндов, только разные 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);
    }

Были ли оба вызова, а затем отключен wifi. Кэш работал отлично для B, но A бросил 504 Unsatisfiable Request (only-if-cached)

Кажется, что в этом случае не удастся перезаписать заголовки.

Ответ 2

Вы должны переписать Request вместо Response. Для справки см. Документы в переписывание запросов. Заметьте, вы также можете использовать класс CacheControl вместо того, чтобы создавать собственный заголовок, если хотите. Ваш перехватчик должен выглядеть примерно так:

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