How to fix browser cache and notmodified respond for JSON? jQuery.ajax({ifModified:true,cache:true}) JSON request break on data respond.

First time browser request http://localhost/api returns status 200 OK and nexts 304 Not Modified

$.ajax({
    type:"GET",
    url:'http://localhost/api', // {"content"="Hello!"}
    dataType:'json',
    cache:true,
    ifModified:true,            // Lets respond `304:notmodified`
    success:function(data,textStatus,jqXHR){
        console.debug(jqXHR.status+':'+textStatus);
        console.debug(data);    // Why on repeated request returns `undefined`?
    }
});

XHR first time returns ok:

200:success
Object {content="Hello!"}

but on next times returns data undefined:

304:notmodified
undefined

How to solve it? It seems jQuery 1.5.1 bug. Expected result:

304:notmodified
Object {content="Hello!"}
3

There are 3 answers

2
Andrew Kennedy On

Try adding a random number to the end of your url as a param.

random_number = Math.floor(Math.random()*10101010101)
url:'http://localhost/api?' + random_number
1
MarkB On

When you receive a 304 you must re-request the data but with the "ifModified" flag set to false. The request will then be subject to normal caching rules and you will receive your cached data.

For instance, in an MVC controller...

        DateTime pageLastUpdated = <.....>

        if (Request.Headers["If-Modified-Since"] != null)
        {
            var dt = DateTime.Parse(Request.Headers["If-Modified-Since"] as string);

            if (pageLastUpdated.Date == dt.Date && pageLastUpdated.Hour == dt.Hour && pageLastUpdated.Minute == dt.Minute && pageLastUpdated.Second == dt.Second) {
              Response.Cache.SetCacheability(HttpCacheability.NoCache);                    
              return new HttpStatusCodeResult(304, "notmodified");
            }
        }

        Response.Cache.SetCacheability(HttpCacheability.Private);
        Response.Cache.SetVaryByCustom("*");
        Response.Cache.SetExpires(pageLastUpdated.AddDays(1));
        Response.Cache.SetLastModified(pageLastUpdated);

        // now return the Json
        return Json(new {........});

The data sent back is cached on the client for up to 1 day.

function loadJson(url, params, onLoaded) {
  // initial request 
  $.ajax({
    type: 'GET',
    dataType: 'json',
    url: url,
    data: params,
    cache: true,
    ifModified: true, // forces check with server
    success: function (result, textStatus, jqXHR) {

        // if 304, re-request the data
        if (result === undefined && textStatus == 'notmodified') {
            $.ajax({
                type: 'GET',
                dataType: 'json',
                url: url,
                data: params,
                cache: true,
                ifModified: false, // don't check with server
                success: function (cachedResult, textStatus, jqXHR) {
                    onLoaded(cachedResult);
                }
            });
        }
        else
            onLoaded(result);
    }
});
0
AudioBubble On

I believe this is how it is supposed to work a 304 doesn't return any data it just tells you it hasn't changed.

However, I do see the problem if you haven't got the data already in memory then you need some method to get it from the browsers cache. Therefore I think the solution is the write code to cache the data.

I am not sure how HTTPS works with etags, however, HTTPs data isn't always cached (different methods and behaviour between browsers and versions) so if etags work you may need to implement your own secure cache anyway.