Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Http Client Caching

In my android application I am trying to cache the response of Http Client. I am testing this task using facebook graph api and have the following url: https://graph.facebook.com/riz.ahmed.52

For the first time I get the "first_name" and display it. Then I change the First Name of my facebook profile and call the same link again. I am expecting to get the old/cached "first_name" but I get the updated one. The console always shows the "The response came from an upstream server" message when I call the url.

My code for Http Client is as follows:

    CacheConfig cacheConfig = new CacheConfig();  
    cacheConfig.setMaxCacheEntries(1000);
    cacheConfig.setMaxObjectSizeBytes(8192);

    //HttpClient httpclient = new CachingHttpClient(new DefaultHttpClient(), cacheConfig);
    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpContext localContext = new BasicHttpContext();

    // Updated code [START]
    httpclient.addResponseInterceptor(new HttpResponseInterceptor() {
        public void process(
            final HttpResponse response,
            final HttpContext context) throws HttpException, IOException {

                 response.removeHeader(response.getFirstHeader("Pragma"));
                 response.removeHeader(response.getFirstHeader("Expires"));

            }                
        });
    // Updated code [END]

    HttpGet httpget = new HttpGet(url);

            // Execute HTTP Get Request
    HttpResponse response = httpclient.execute(httpget, localContext);
    HttpEntity entity = response.getEntity();
    String res = EntityUtils.getContentCharSet(entity);

    CacheResponseStatus responseStatus = (CacheResponseStatus) localContext.getAttribute(
        CachingHttpClient.CACHE_RESPONSE_STATUS);

    switch (responseStatus) {
        case CACHE_HIT:
            System.out.println("A response was generated from the cache with no requests " +
                "sent upstream");
            break;
        case CACHE_MODULE_RESPONSE:
                System.out.println("The response was generated directly by the caching module");
                break;
        case CACHE_MISS:
                System.out.println("The response came from an upstream server");
                break;
        case VALIDATED:
                System.out.println("The response was generated from the cache after validating " +
                        "the entry with the origin server");
                break;
            }

I am using Android 2.3.3. Please let me know what I am missing here

like image 320
rizzz86 Avatar asked May 29 '12 08:05

rizzz86


1 Answers

The page you are loading specifies a Expires:Sat, 01 Jan 2000 00:00:00 GMT header, i.e. it's always considered stale and must always be re-fetched.

Edit:

Also returns a Pragma: no-cache apparently. Basically, it's telling your HTTP client to never cache this page. You may be able to remove these headers with a HttpResponseInterceptor if you're dead-set on caching the response.

#2 Edit:

Using http-clientcache-4.2.jar is going to be problematic as it is not completely compatible with the version of the HTTP client packaged with the Android SDK - you're going to get NoClassDefFoundErrors and similar nonsense when using it.

However - if you "build-your-own" by downloading the source for clientcache-4.2 and strip out any unfulfilled references (such as refactoring the package name of the commons logging) & killing of all the annotations sprinkled throughout the code (etc.) you can probably get a working version. If you do, this worked:

class MakeCacheable implements HttpResponseInterceptor {
    public static MakeCacheable INSTANCE = new MakeCacheable();
    public void process(HttpResponse resp, HttpContext ctx) throws HttpException, IOException {
        resp.removeHeaders("Expires");
        resp.removeHeaders("Pragma");
        resp.removeHeaders("Cache-Control");
    }
}

Injected into the DefaultHttpClient used by the CachingHttpClient like so:

DefaultHttpClient realClient = new DefaultHttpClient();
realClient.addResponseInterceptor(MakeCacheable.INSTANCE, 0); // This goes first
CachingHttpClient httpClient = new CachingHttpClient(realClient, cacheConfig);

If an entry is cached or not is decided by the ResponseCachingPolicy which unfortunately is a final in the CachingHttpClient, but looking through it will show all the headers that need to go to make an un-cacheable entry cacheable.

like image 197
Jens Avatar answered Sep 28 '22 07:09

Jens