Проблемы при попытке использовать If-None-Match с Etag в Android

#android #caching #retrofit2 #okhttp #etag

#Android #кэширование #retrofit2 #okhttp #etag

Вопрос:

Всегда возвращает код 200 (ответ ok), когда он должен быть 304.

Вот мой пример кода.

 import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Streaming
import retrofit2.http.Url

interface DownloadService {
    @Streaming
    @GET
    suspend fun downloadResourceIfNoneMatch(
        @Url url: String,
        @Header("If-None-Match") vararg eTags: String
    ): Response<ResponseBody?>
}
  

Вот мой OkHttpClient, который я использую:

 val cacheSize: Long = 10 * 1024 * 1024 // 100 MB
val cache = Cache(context.cacheDir, cacheSize)
val cacheControlInterceptor = CacheControlInterceptor(context)
return OkHttpClient.Builder()
    .cache(cache)
    .addInterceptor(cacheControlInterceptor)
    .addNetworkInterceptor(cacheControlInterceptor)
    .addNetworkInterceptor(loggingInterceptor)
    .build()
  

Вот мой класс CacheControlInterceptor:

 import android.content.Context
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import timber.log.Timber
import java.io.IOException

class CacheControlInterceptor constructor(val context: Context) : Interceptor {
    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        Timber.d("cache control interceptor")
        var request: Request = chain.request()
        if (request.method == "GET") {
            request = request.newBuilder()
                .build()
        }
        val originalResponse: Response = chain.proceed(request)
        return originalResponse.newBuilder()
            .header("Cache-Control", "private, must-revalidate")
            .build()
    }
}
  

Вот как я делаю запрос:

 val response: Response<ResponseBody?> = downloadService.downloadResourceIfNoneMatch(downloadUrl, "2377a02e14b7df5100ee9ffebbb8443a")
  

Я использую жестко заданный ETag для тестирования. Когда запрос выполняется дважды, он не отображает ожидаемое поведение (т.Е. Код ответа 304). Повторный запрос приводит к нулевому cacheResponse и коду ответа 200.

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

Ответ №1:

OkHttp не сохранит ответ в кэше, если вы не прочтете его полностью. Он записывает кэш как побочный эффект чтения тела ответа.

Если вы прекратите чтение до завершения тела ответа, OkHttp не получит полного ответа для сохранения, и запись в кэше будет недоступна.

Комментарии:

1. Я видел аналогичный ответ, опубликованный на аналогичный вопрос. Это мне не очень помогло, поскольку я считаю, что публикую чтение всего тела ответа (хотя я могу ошибаться). Я читаю полный ответ и закрываю поток по завершении. Есть ли способ проверить, что ответ был прочитан полностью или нет? Вы случайно не знаете, где находится кэш OkHttp в файлах устройства, возможно, чтобы я мог перепроверить? Я предположил, что он будет сохранен в указанной пользователем папке кэша во внутренних файлах приложения.

2. Вы можете использовать API прослушивателя событий для просмотра всех событий, включая кэширование square.github.io/okhttp/caching . Это может дать дополнительное объяснение.