Proper way to handle 304 not modified in jQuery ajax

Scott picture Scott · Mar 7, 2011 · Viewed 24k times · Source

As of jQuery 1.5, the ajax methods now correctly handle 304 Not Modified responses by calling the success() handler, as per the W3C spec for XMLHTTPRequest. This allows your application to treat the request as being successful, even if the server didn't actually return any data (because you already have the latest data cached).

For a normal (uncached) GET request, the success handler is called with the following args:

  • data: { the data from the server }
  • status: OK
  • jqXHR:
    • status: 200
    • statusText: OK
    • responseText: { the data from the server }

For a cached GET request, the success handler is called with the following args:

  • data: undefined
  • status: notmodified
  • jqXHR:
    • status: 304
    • statusText: notmodified
    • responseText: { the data from the cache }

(at least, this is how it is returned in IOS 4.2, for a web-app that uses the application cache via a manifest file. I'm assuming this is consistent for general browser caching on most platforms/browsers).

You can see that the "data" argument is only populated if the request was 200 OK; where as the jqXHR.responseText is always populated with data, regardless of whether that data came from the server (200 OK) or from the cache (304 Not Modified).

Given that, in most GET requests, your success handler is going to want to do something with the data you got regardless of where it came from, it would seem to make the most sense for your success code to always use the jqXHR.responseText, rather than doing something like this:

if ("notmodified" === status) {
  // do something with jqXHR.responseText
} else {
  // do something with data
}

Or is there ever a case when jqXHR.responseText wouldn't be populated in the success handler, but the data arg would?

I have to go through my codebase and change all success handlers (previously I was on jQuery 1.4.2, which always returned data, even from the cache); so I just want to make sure I'm handling it the right way. (Don't wan't to get to the end and then realise I should have done it another way).

Answer

Scott picture Scott · Mar 7, 2011

I've just spotted the obvious flaw in my question....I was assuming that the data was always text, so using jqXHR.responseText in preference to the data argument made sense.

But in the case that the dataType is JSON, JSONP, script etc...if the data returned in a 304 Not Modified response comes back as undefined, you'd need to convert the jqXHR.responseText from a string to the desired type first, eg.

if (data === undefined) {
  data = $.parseJSON(jqXHR.responseText);
}

...and you'd only want to do this (potentially expensive) conversion when you need really to.

Kinda makes sense now that I think about it...data is always going to be what came back from the server (which in some cases might not be undefined for a 304...eg. the server could return some additional text/html); which allows the developer the flexibility to choose what they want to do in the event of a 304, eg.

  • Display the response from the server (if any)
  • Use the jqXHR.responseText
  • Do something else entirely...