Retrofit: Adding cache-control to headers has no effect?

Created on 2 Jan 2015  ·  7Comments  ·  Source: square/retrofit

I added @Headers("Cache-Control: public,max-age=86400,s-maxage=86400") annotation in my RestService interface but i guess it has no effect. My request takes the same time to fetch and load data every time.

Can you explain what this header actually does to my request ? And how do I cache the response so that next time when i request the same data i get it fast from cache without hitting the server?

I build my adapter like:

        Type listType = new TypeToken<ArrayList<Category>>() {}.getType();

        Gson gson = new GsonBuilder()
                .registerTypeAdapter(listType, new AllCategoryDeserializer())
                .create();

        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(Constants.API_ENDPOINT)
                .setConverter(new GsonConverter(gson))
                .build();

Most helpful comment

Use networkInterceptors()

All 7 comments

The Cache-Control header when added on the request has very little control over what happens. Some of the options are no-cache (do not use the cache to fulfill the request), no-store (do not store the response in the cache), and max-age (allow cache responses that are up to a certain age).

The Cache-Control header on the response is what determines if a response is able to be cached. The server must include the header with appropriate options in order for the HTTP client to cache it (assuming the HTTP client has a disk cache and it is properly configured. Retrofit does no caching).

OkHttp 2.2 has a new feature called interceptors which would allow you to add a Cache-Control header despite the server not sending it. This is very dangerous but very powerful. Usually you would only do this in extreme cases. A similar issue is here: https://github.com/square/okhttp/issues/1265

Thank you, i got your point but have an absurd doubt.

If Cache-Control header in the response (which is added by the server) is responsible for caching in the client-side then why are we adding the header while making the request to the server?

@JakeWharton I use the retrofit 2.0.0-snapshot version and okhttp-2.2.0. I found there is different Http Header in retrofit logs and cache file in disk. The Cache-Control didn't change by REWRITE_CACHE_CONTROL_INTERCEPTOR. Here is my code for build a okhttpclient for retrofit.

    public static Client buildOkHttpClient(boolean cacheEnable) {
        Cache cache;
        OkHttpClient client = new OkHttpClient();
        if (cacheEnable) {
            File cacheDirectory = new File(MainApplication.getInstance().getCacheDir().getAbsolutePath(), "OKHttpCache");
            try {
                cache = new Cache(cacheDirectory, CACHE_SIZE);
                client.setCache(cache);
            } catch (IOException e) {
                e.printStackTrace();
            }
            client.setAuthenticator(AUTHENTICATOR);
        }
        client.interceptors().add(REWRITE_CACHE_CONTROL_INTERCEPTOR);
        return new OkClient(client);
    }

    /** Dangerous interceptor that rewrites the server's cache-control header. */
    private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
        @Override public Response intercept(Chain chain) throws IOException {
            Response originalResponse = chain.proceed(chain.request());
            return originalResponse.newBuilder()
                    .header("Cache-Control", String.format("max-age=%d, only-if-cached, max-stale=%d", MAX_AGE, MAX_STALE))
                    .build();
        }
    };

Log Header:

01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ <--- HTTP 200 http://zhangfei.wusi.com/v1/products (285ms)
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ Content-Type: application/json; charset=utf-8
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ Transfer-Encoding: chunked
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ Connection: keep-alive
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ Vary: Accept-Encoding
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ Status: 200 OK
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ X-Frame-Options: SAMEORIGIN
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ X-XSS-Protection: 1; mode=block
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ X-Content-Type-Options: nosniff
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ X-Request-Id: ca5b0139-aba5-4ab7-9d3a-8e646e67b8a1
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ X-Runtime: 0.128336
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ X-Powered-By: Phusion Passenger 4.0.53
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ Date: Mon, 05 Jan 2015 11:55:54 GMT
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ Server: nginx/1.6.2 + Phusion Passenger 4.0.53
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ OkHttp-Selected-Protocol: http/1.1
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ OkHttp-Sent-Millis: 1420458953573
01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ OkHttp-Received-Millis: 1420458953759
**01-05 19:55:53.756  32160-32204/com.wusi.wusiapp.debug D/Retrofit﹕ Cache-Control: max-age=60, only-if-cached, max-stale=2419200**

The Header file in cache folder:

``` http://zhangfei.wusi.com/v1/products
GET
1
Accept-Encoding: gzip
HTTP/1.1 200 OK
18
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Status: 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: ca5b0139-aba5-4ab7-9d3a-8e646e67b8a1
X-Runtime: 0.128336
X-Powered-By: Phusion Passenger 4.0.53
Date: Mon, 05 Jan 2015 11:55:54 GMT
Server: nginx/1.6.2 + Phusion Passenger 4.0.53
Content-Encoding: gzip
OkHttp-Selected-Protocol: http/1.1
OkHttp-Sent-Millis: 1420458953573
OkHttp-Received-Millis: 1420458953759

```

The Header in disk cache folder stil as same as server, so the cache strategy didn't work.

Use networkInterceptors()

Why the application interceptor does not work and Network Interceptor work?

@pc9292 because okhttp client use the response from the network interceptor to decide whether it should store the response in the cache.

@pc9292 See the diagram here for detail on why its a network interceptor vs. and application interceptor. Application interceptors intercept the request/response between the caller and the OkHttp client. Network interceptors intercept the request/response between the server and the OkHttp client.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kkunsue picture kkunsue  ·  3Comments

starktonys picture starktonys  ·  3Comments

JerzyPuchalski picture JerzyPuchalski  ·  3Comments

ramonmoraes8080 picture ramonmoraes8080  ·  3Comments

jpshelley picture jpshelley  ·  4Comments