in Ajax

XMLHttpRequest and Caching

A lot has been written about caching issues with XMLHttpRequest based apps. There is certainly some amount of frustration and confusion about this topic. I had the same kind of experience when I updated my blog recently to show a paginated blog entry list via an XMLHttpRequest. I noticed that mainstream browsers behave inconsistently when it comes to caching.

Current releases of Firefox (1.1.7) and Internet Explorer (6.0) handle caching of content downloaded via XMLHttpRequest quite differently.

Firefox 1.1.x does not allow the content download via an XMLHttpRequest to be cached. Although this gives the user a chance to to see the latest content on every request, the downside is increased traffic and bandwidth usage. For example, with Firefox, request for every page in the paginated entry listing on my blog causes an extra network roundtrip to fetch that page, followed by some extra cycles on the server to generate the content.

I looked at the request and response headers that Firefox was sending and receiving. The request included the following headers.

Pragma: no-cache 
Cache-Control: no-cache

These headers imply that every intermediary (like a caching proxy) and the web server should ignore all caching headers, and MUST send the complete response. For example, this header prevents the web server to responsd with a 304 Not Modified response header and skip sending the content. In effect, these headers force the server to return fresh content on every request. Why would a HTTP client want to send such headers? I can only think of two use cases. Either the client cannot cache the response, or it has lost previously cached response. But servers cannot return a 304 Not Modified response header when there is no conditional request header (such as an If-Modified-Since header).

I checked the Rico script that I used to generate entry list pages for any caching headers that the script could be sending. There were none. So, these request headers were not added by the script, but by Firefox. After some searching, I found that this is a known bug in Firefox. This has been fixed in the latest Firefox 1.5 Beta 2 release. I am not aware of any work-arounds for this bug.

On the other extreme, Internet Explorer 6.0 always shows stale content. Once Internet Explorer downloads the content via an XMLHttpRequest, it caches it, and never bothers to check for updates. I came across a number of solutions that developers were using to get around this problem. One often mentioned solution was to add some random query parameter to the URL so that it will force the browser to treat each request differently disregarding all caching issues. Solutions like this are inefficient as they bypass caching completely.

The source of the problem turned out be an inconsistency with the heuristic algorithm that Internet Explorer uses to decide its caching behavior for resources that do not specify response caching headers.

Internet Explorer uses four browser-specific settings to influence browser caching. These settings read like "check for new versions of stored pages on every visit to the page, every time you start Internet Explorer, automatically, or never". Of these settings, "automatically" is the default setting. As discussed in this MSDN article, this default setting causes Internet Explorer to use a heuristic algorithm to decide its behavior for caching responses that do not contain caching headers. I could not find any reference to known issues with regards to this algorithm, and my guess is that this algorithm does not treat XMLHttpRequest responses the same as regular http responses. The result is that Internet Explorer caches the response forever (subject to its flush policies) for XMLHttpRequests. When I added the script to generate the XML for entry list, I did not bother to add any caching headers to the response (I fixed this later). This caused Internet Explorer to use this algorightm. So, if you are using XMLHttpRequest and find that the browser is not refreshing the page, this might be the reason.

It is easy to fix this problem. To get Internet Explorer not use this heuristic algorithm for caching, add whatever caching headers are appropriate to the response on the server side. When caching headers are present in a response, Internet Explorer uses those headers to decide whether to cache a response, and when cached, how long to cache it, and when to invalidate it.

Write a Comment

Comment

12 Comments

  1. I have posted a handful of bug reports to some AJAX libraries about this issue but they were dismissed. Thank you for researching this matter and providing your results. I hope more AJAX library authors read about this issue and make what fixes they can to them.

  2. to get non-cached-results from internet-explorer you might also want to send the If-Modified-Since-header with a value of jan 1, 1970 (or new Date(0), for javascript)

    does the same as setting cache-control/pragma-headers on the server-side.

  3. A simple “Expires: -1″ from the server would do the trick if you don’t want IE6/7 to cache RPC responses. I found “Cache-Control: no-cache” did not work.

  4. Experiments indicate that Expires: -1 only mostly works (MSIE 6.0.2900.5512.xpsp.080413-2111). If you do the requests quickly enough, you may still see cached data for some of them. Specifically, you get cached data if you issue a new XMLHttpRequest within 2 seconds of the old one.

  5. xmlhttp.setRequestHeader(’Pragma’, ‘Cache-Control: no-cache’);
    this didn’t work for me. Apparently setRequestHeader is not a method of the xmlhttp object.
    Instead what I have read in a forum is that even if you do set no-cache and all that stuff on the returned xml from the server, the browsers will still cache if the xmlhttp requests are called in an interval smaller than 2 seconds. And this was actually my problem.
    Still I would like to make requests farter than that so if you know any working solution, reply here.

      • YES, YES, YES!!!

        This was not enough for IE8 (while worked in FF):
        req.setRequestHeader(“Cache-Control”, “no-cache”);
        req.setRequestHeader(“Pragma”, “no-cache”);

    • Awesome Works great – For IE8

      xmlHttp.open("GET", URL, true);
      xmlHttp.setRequestHeader("Cache-Control", "no-cache");
      xmlHttp.setRequestHeader("Pragma", "no-cache");
      xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");

  6. This worked for me:

    req.open “GET”, Url, False
    req.setRequestHeader(“Cache-Control”, “no-cache”)
    req.send

  7. Hi
    ///To Create XMLHttpRequest for cross browser
    function Xhr() {
    try {
    return new XMLHttpRequest();
    }
    catch (e) {
    }
    try {
    return new ActiveXObject(“Msxml3.XMLHTTP”);
    }
    catch (e) {
    }
    try {
    return new ActiveXObject(“Msxml2.XMLHTTP.6.0″);
    }
    catch (e) {
    }

    try {
    return new ActiveXObject(“Msxml2.XMLHTTP.3.0″);
    }
    catch (e) { }

    try {
    return new ActiveXObject(“Msxml2.XMLHTTP”);
    }
    catch (e) { }

    try {
    return new ActiveXObject(“Microsoft.XMLHTTP”);
    }
    catch (e)
    { }
    return null;
    }

    and

    var xhr = Xhr(); //Create XMLHttpRequest
    var formdata=new FormData();
    xhr.open(‘POST’,’/MyCourseAdmin/AddNewCourses’,true);
    xhr.timeout= 120000;
    xhr.send(formdata);

    In IE 8 & 9 it gives error while xhr.send(formdata)

    Please help me
    Thank in advance