Issues trying to use If-None-Match with Etag in Android

Viewed 264

Always returns code 200 (response ok) when it should be 304.

Here is my example code.

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?>
}

Here's my OkHttpClient that I am using:

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()

Here's my CacheControlInterceptor class:

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()
    }
}

Here is how I am making the request:

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

I am using a hard-coded ETag for testing. When the request is made twice, it does not display the expected behavior (i.e. response code 304). The repeated request results in a null cacheResponse and a response code of 200.

I am seeing the expected debug log output, so it seems like the CacheControlInceptor is instantiating properly. I am getting the ETag in the response. The responses are caching properly in the context's cache directory. I cannot figure out what is wrong.

1 Answers

OkHttp won't save the response to the cache unless you read it fully. It writes the cache as a side-effect of reading the response body.

If you stop reading before the response body is complete, OkHttp doesn't have a full response to store and the cache entry will not be available.

Related