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

Обнаружение ответа 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); // ???
});
4b9b3361

Ответ 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