Подтвердить что ты не робот

Модернизация ETAG и кэширование

Есть ли правильное объяснение того, как добавить кеширование и ETAG/If-None-Match поддержка Retrofit + OkHttp? Я пытаюсь добавить поддержку ETAG на 2 проекта, и сначала я подозревал, что может быть проблема с заголовками HTTP, у другого проекта все правильно настроено, и кеширование все еще не работает должным образом.

Ниже приводятся мои попытки заставить его работать. Результаты показывают, что кеширование работает в одном экземпляре приложения, но как только я перезапущу - все снова загружается. Кроме того, в моих журналах я не заметил, что If-None-Match добавлен в запрос, поэтому я предполагаю, что сервер не знает о ETAG и полностью пересчитывает ответ.

Вот несколько примеров кода:

public class RetrofitHttpClient extends UrlConnectionClient
{

    private OkUrlFactory generateDefaultOkUrlFactory()
    {
        OkHttpClient client = new com.squareup.okhttp.OkHttpClient();

        try
        {
            Cache responseCache = new Cache(baseContext.getCacheDir(), SIZE_OF_CACHE);
            client.setCache(responseCache);
        }
        catch (Exception e)
        {
            Logger.log(this, e, "Unable to set http cache");
        }

        client.setConnectTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS);
        client.setReadTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS);
        return new OkUrlFactory(client);
    }

    private final OkUrlFactory factory;

    public RetrofitHttpClient()
    {
        factory = generateDefaultOkUrlFactory();
    }

    @Override
    protected HttpURLConnection openConnection(retrofit.client.Request request) throws IOException
    {
        return factory.open(new URL(request.getUrl()));
    }
}

Адаптер отдыха затем создается с FULL уровнем журнала и пользовательским тегом:

restAdapter = new RestAdapter.Builder()
        .setClient(new RetrofitHttpClient())
        .setEndpoint(Config.BASE_URL)
        .setRequestInterceptor(new SignatureSetter())
        .setConverter(new JacksonConverter(JsonHelper.getObjectMapper()))
        .setLogLevel(RestAdapter.LogLevel.FULL)
        .setLog(new AndroidLog("=NETWORK="))
        .build();

У меня есть длинный запрос на первом экране приложения для тестирования. Когда я открываю приложение, для завершения запроса требуется 7 секунд. Если я приостанавливаю и возобновляю приложение - тот же запрос принимает 250 мс, явно попадая в кеш. Если я полностью закрываю приложение и перезагружаюсь - он снова занимает 7 секунд.

UPDATE: Как было предложено, я использовал обычную сборку Retrofit и подключил LoggingInterceptor. Вот что я получаю.

Received response for *** in 449,3ms
Date: Wed, 07 Jan 2015 09:02:23 GMT
Server: Apache
X-Powered-By: PHP/5.4.31
Access-Control-Allow-Credentials: true
Pragma:
Cache-Control: public, max-age=3600
X-Frame-Options: SAMEORIGIN
Etag: "hLxLRYztkinJAB453nRV7ncBSuU=-gzip"
Last-Modified: Wed, 24 Dec 2014 13:09:04 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
OkHttp-Selected-Protocol: http/1.1
OkHttp-Sent-Millis: 1420621288104
OkHttp-Received-Millis: 1420621288554


Sending request **** on Connection{****:80, [email protected] hostAddress=**** cipherSuite=none protocol=http/1.1}
Accept: application/json;
Host: ****
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/2.2.0

Response is equal to described above

Как вы можете видеть, заголовок If-None-Match присутствует в следующем запросе.

4b9b3361

Ответ 1

Я вижу, что этот вопрос продолжает привлекать внимание, и как только я не смогу ответить на этот вопрос, я могу выбрать из него - я сейчас изучаю тему и закрываю нить.

Конечный результат исследования и некоторые обсуждения в потоках модифицированной и okhttp на GitHub заключались в том, что в OkHttp, возможно, была проблема, которая могла бы предотвратить использование тега If-None-Match для исходящих запросов.

Проблема должна была быть исправлена ​​в OkHttp 2.3, и я использую "предположительно" здесь, потому что я еще не тестировал, действительно ли это работает. Тестирование было затруднительным, потому что я использовал Retrofit, а сама Retrofit пришлось обновить, чтобы использовать новую версию OkHttp и добавить новую поддержку Interceptors, чтобы иметь возможность отлаживать все заголовки, установленные OkHttp. Связанная с этим тема: https://github.com/square/okhttp/issues/831

Я не уверен, что после этого была обновлена ​​Retrofit. Надеюсь, это было так, поэтому есть хороший шанс, что проблема уже исправлена, и Etag должен работать правильно - просто убедитесь, что у вас есть последние версии Retrofit и OkHttp.

Я попытаюсь все проверить самостоятельно, как только у меня будет время.

Ответ 2

Использование перехватчиков OkHttp поможет вам диагностировать заголовки, входящие и выходящие из вашего приложения. В документе interceptors doc приведен пример кода перехватчика, который регистрирует заголовки запросов и ответов в сети. Вы можете использовать это как есть.

class LoggingInterceptor implements Interceptor {
  @Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();

    long t1 = System.nanoTime();
    logger.info(String.format("Sending request %s on %s%n%s",
        request.url(), chain.connection(), request.headers()));

    Response response = chain.proceed(request);

    long t2 = System.nanoTime();
    logger.info(String.format("Received response for %s in %.1fms%n%s",
        response.request().url(), (t2 - t1) / 1e6d, response.headers()));

    return response;
  }
}

Чтобы подключить его к "Дооснащению", вам нужно получить предварительный снимок "Дооснащения". По состоянию на январь 2015 года обновляемые версии Retrofit не участвуют в перехватчиках OkHttp. Скоро будет выпуск, но он еще не готов.

Ответ 3

У меня была аналогичная проблема: OkHttp не ударил кеш, даже когда сервер отправлял один и тот же ETAG.

Моя проблема была SIZE_OF_CACHE. Я определял очень маленький размер.

Попробуйте увеличить его (что-то вроде 10 * 1024 * 1024 работает для меня) Также вы можете исследовать/data/data//файлы/кеш, чтобы увидеть, есть ли там что-то, хранящееся там.