Правильный способ настройки кэша для OkHttp в Android

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

в настоящее время его кэширование ответа, но не использует его при повторном запросе ресурса. Может быть, это не то, как он должен был использоваться.

я настраиваю OkHttpClient с кэшем, как это:

public static Cache createHttpClientCache(Context context) {
    try {
        File cacheDir = context.getDir("service_api_cache", Context.MODE_PRIVATE);
        return new Cache(cacheDir, HTTP_CACHE_SIZE); 
    } catch (IOException e) {
        Log.e(TAG, "Couldn't create http cache because of IO problem.", e);
        return null;
    }
}

это используется следующим образом:

if(cache == null) {
    cache = createHttpClientCache(context);
}
sClient.setCache(cache);

вот как я делаю один из запросов к серверу с OkHttp, который фактически не использует кэш:

public static JSONObject getApi(Context context) 
        throws IOException, JSONException, InvalidCookie {

    HttpCookie sessionCookie = getServerSession(context);
    if(sessionCookie == null){
        throw new InvalidCookie();
    }
    String cookieStr = sessionCookie.getName()+"="+sessionCookie.getValue();

    Request request = new Request.Builder()
        .url(sServiceRootUrl + "/api/"+API_VERSION)
        .header("Accept", "application/json")
        .header("Cookie", cookieStr)
        .build();

    Response response = sClient.newCall(request).execute();
    if(response.code() == 200){
        String charset = getResponseCharset(response);
        if(charset == null){
            charset = "utf-8";
        }
        String responseStr = new String(response.body().bytes(), charset);
        response.body().close();
        return new JSONObject(responseStr);
    } else if(response.code() == 401){
        throw new InvalidCookie();
    } else {
        return null;
    }

}

если я попаду в каталог, который я указал в качестве кэша для OkHttp, я могу увидеть файл журнала и 4 других файла, которые содержат ответы на некоторые из запросов. Этот запрос (/api, который я только что вставил код) хранится в каталоге кэша, поэтому он был действительно кэширован, но имя файла имеет .tmp в конце, например, если он не был правильно сохранен в окончательный файл, как и другой запрос, который я сделал.

так выглядит заголовок ответа сервера на запрос:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Expires: Sat, 09 Aug 2014 19:36:08 GMT
Cache-Control: max-age=86400, must-revalidate
Last-Modified: Sun, 04 Aug 2013 15:56:04 GMT
Content-Length: 281
Date: Fri, 08 Aug 2014 19:36:08 GMT

и вот как OkHttp хранит его в кэше:

{HOST}/api/0.3
GET
0
HTTP/1.1 200 OK
9
Server: Apache-Coyote/1.1
Expires: Sat, 09 Aug 2014 19:36:08 GMT
Cache-Control: max-age=86400, must-revalidate
Last-Modified: Sun, 04 Aug 2013 15:56:04 GMT
Content-Length: 281
Date: Fri, 08 Aug 2014 19:36:08 GMT
OkHttp-Selected-Protocol: http/1.1
OkHttp-Sent-Millis: 1407526495630
OkHttp-Received-Millis: 1407526495721

после того, как OkHttp создает этот файл, он продолжает запрашивать на сервере тот же ресурс. Я вижу эти сообщения в Wireshark.

что я делаю не так?

обновление:

это теперь ответ сервера после предложения Джесси:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Expires: Thu, 14 Aug 2014 18:06:05 GMT
Last-Modified: Sun, 10 Aug 2014 12:37:06 GMT
Content-Length: 281
Date: Wed, 13 Aug 2014 18:06:05 GMT

обновление 2: Попробовал версию кода и выяснил, что вполне вероятно, что где-то есть ошибка в отношении кэша. Это то, что я получил от выхода Maven:

Results :

Failed tests: 
  CacheTest.conditionalHitUpdatesCache:1653 expected:<[A]> but was:<[B]>

Tests in error: 
  CallTest.tearDown:86 » IO failed to delete file: C:UsersAdrianAppDataLocal...

Tests run: 825, Failures: 1, Errors: 1, Skipped: 17

более полный журнал можно увидеть здесь:https://gist.github.com/16BITBoy/344ea4c22b543f397f53

3 ответов


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

проблема была довольно простой, и это было то, что другой из методов запроса получал тело на ответ, и он не был закрыт в конце. Это объясняет, почему я видел ".tmp " файл в кэше, но все же запутанный и вводящий в заблуждение из-за того, что этот метод запроса потреблял и закрывал тело из ответа. Похоже блокировка или монитор для редактора кэша является глобальным для всех запросов, а не по запросу. Я, хотя это не было, когда я читал код, когда он использовал хэш для запроса в качестве ключа.

во всяком случае, это было :D

С этого момента я попытаюсь придерживаться такого шаблона...

String respBody = null;
if(response.body() != null) {
    respBody = response.body().string();
    response.body().close();
}

...перед обработкой каждого случая для кода ответа. Таким образом, я не пропущу близкого контакта с телом ответа.


ваш сервер принудительно проверяет кэш с помощью этого заголовка ответа:

Cache-Control: max-age=86400, must-revalidate 

удалите это, и вам должно быть хорошо идти.


У меня такая же проблема, затем я отлаживаю исходный код okhttp, вы можете посмотреть на CacheStrategy.cacheResponseAge (), okhttp будет использовать сама наумилялась и servedDate, servedDate-это получить от вас HTTP-заголовок сервера "дата", nowMillis-это получить с вашего android-устройства. Поэтому, когда время сервера позже времени устройства, okhttp не будет получать из кэша, если max-age мал.

Прости мой бедный английский ^_^