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();
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.
Most helpful comment
Use
networkInterceptors()