Обнаружение ответа OkHttp из кеша (с помощью Retrofit)

Есть ли способ определить, приходит ли ответ Retrofit из настроенного кэша OkHttp или является живым ответом?

Определение клиента:

Cache cache = new Cache(getCacheDirectory(context), 1024 * 1024 * 10);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .cache(cache)
            .build();

Определение Api:

@GET("/object")
Observable<Result<SomeObject>> getSomeObject();

Пример вызова:

RetroApi retroApi = new Retrofit.Builder()
            .client(okHttpClient)
            .baseUrl(baseUrl)
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(RetroApi.class);

result = retroApi.getSomeObject().subscribe((Result<SomeObject> someObjectResult) -> {
     isFromCache(someObjectResult); // ???
});

Ответ 1

В любое время, когда вы okhttp3.Response (retrofit2.Response.raw()), вы можете проверить, является ли ответ кешем.

Процитировать Джесси Уилсон:

Есть несколько комбо.

. networkResponse() только - ваш запрос был подан только из сети.

. cacheResponse() только - ваш запрос был отправлен исключительно из кеша.

.networkResponse() и .cacheResponse() - ваш запрос был условным GET, поэтому заголовки из сети и тела из кеша.

Итак, для вашего примера метод isFromCache будет выглядеть так:

boolean isFromCache(Result<?> result) {
  return result.response().raw().networkResponse() == null;
}

Ответ 2

Решение 1:

Используя okhttp3.Response.cacheResponse(), вы можете проверить, был ли получен ответ от кеша:

Возвращает необработанный ответ, полученный из кеша. Будет null, если этот ответ не использовал кеш

Чтобы получить необработанный ответ OkHttp от вашего адаптационного ответа, используйте .raw(). то есть:.

public boolean isFromCache(Result<?> retroResult) {
    return retroResult.response().raw().cacheResponse() != null;
}

Решение 2:

Вы можете добавить Interceptor к клиенту OkHttp через new OkHttpClient.Builder().addInterceptor(...). В этом перехватчике получить ответ через chain.proceed(chain.request). Затем используйте Response.cacheResponse() соответственно Response.networkResponse(), чтобы определить, откуда пришел ответ.

Полный код:

new OkHttpClient.Builder().addInterceptor(chain -> {
        Response response = chain.proceed(chain.request());
        if (response.cacheControl() != null) {
            // from cache
        } else if (response.networkResponse() != null) {
            // from network
        }
        return response;
});

Ответ 3

if (response.raw().cacheResponse() != null) {  
    // true: response was served from cache
}

if (response.raw().networkResponse() != null) {  
    // true: response was served from network/server
}

Но я бы посоветовал вам проверить, является ли ваш networkResponse нулевым, поскольку после того, как запрос будет кэширован, и у вас есть сетевой ответ, ваш ответ передается потоком из сети, а не в кеш (в зависимости от maxStale, который вы, возможно, указали на CacheControl). Поэтому проверьте, не является ли networkResponse нулевым, если null и ваш cacheResponse не являются нулевыми, ответ будет отправлен из кэша иначе наоборот.

Ответ 4

Слишком поздно, но, возможно, это будет полезно для кого-то. Когда контент поступает из сети: response.networkResponse() и response.cacheResponse() не равны NULL, когда контент поступает из кеша response.networkResponse() имеет значение NULL, поэтому код из @sebastian:

new OkHttpClient.Builder().addInterceptor(chain -> {
        Response response = chain.proceed(chain.request());
        if (response.cacheControl() != null) {
            // from cache
        } else if (response.networkResponse() != null) {
            // from network
        }
        return response;
});

просто замените этим кодом:

OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addInterceptor(new Interceptor() {
    @NonNull
    @Override
    public Response intercept(@NonNull Chain chain) throws IOException {
        Response response = chain.proceed(chain.request());
        if (response.networkResponse() != null) {
            Log.v(TAG, "Response from networkResponse(): " + response.networkResponse());
        } else if (response.cacheResponse() != null) {
            Log.v(TAG, "Response from cacheControl(): " + response.cacheResponse());
        }
        return response;
    }
});

Ответ 5

Ответ приходит из кэша, если cacheResponse существует и networkResponse (если существует) имеет код ответа 304. См: https://github.com/square/okhttp/issues/4539