0

I am working with a particularly expensive (in terms of query and also bandwidth), think of it as a catalog of items. However, the catalog also needs to be comletely accurate at all times, i.e. updates to the catalog need to be reflected in real-time so a fixed cache expiration period will not work.

The catalog is currently being requested by the client using JQuery 1.8.2 exactly like this:

    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "http://myserver.com/somejsonquery.aspx",
        data: {},
        dataType: "json",
        success: function ( ... ) { ... },
        error: function ( ... ) { ... }
        });

And the result is properly formatted JSON with "application/json" content type.

Since I maintain a reliable cache on the server side, I'd really like to implement If-Modified-Since semantics so that my server can return 304 when the cache is current (without incurring the DB or network hit), and only send the new catalog to the client if a reload occurred since the "If-Modified-Since" timestamp.

However, I am having trouble getting this to work (at least on IE). I tried setting the following and still couldn't get the client to send If-Modified-Since:

  • set "cache: true" on the JSON request
  • make the server return "Cache-control: private" HTTP header in the response

Anyone with any insight on this?

As a follow up, I also wonder if I set the Cache-control to "public" (i.e. cachable by proxy servers), would the cache consistency still be maintained through the proxies? i.e. will the proxy check back to my server every time a client requests that page. If I were to enable proxy caching, I need to be completely sure that the proxy will guarantee a consistent cache state.

I've been stuck on this for a while, so any help will be appreciated!

Thanks, - K.

Keith L
  • 33
  • 1
  • 7

2 Answers2

1

Getting cache headers etc to be cross browser compatible is not an exact science. If you don't mind getting a network hit, try this.

1) Attach a unique id to your catalog and send it to the client as well as return it in your ajax request.

2) Test whether that unique ID matches the most updated version of your cached catalog. If it does, return the 304 response code, else return the new catalog along with the new unique ID.

Brad M
  • 7,857
  • 1
  • 23
  • 40
  • Thanks Brad, but this implies that the client needs to store both the unique ID and catalog data somewhere, right? My intent of using the If-Modified-Since header is to push the caching (and management) of the data to the native browser implementation so my code does not need to explicitly manage the cached content. I want my code to be stateless and not have to be worried about storing and managing cached content. My knowledge here might be incomplete, so apologies if I am making the wrong assumptions. – Keith L Mar 01 '13 at 18:02
  • Relying on native browser implementations of caching ajax requests is not a good practice. See the following thread for an example of why http://stackoverflow.com/questions/12506897/is-safari-on-ios-6-caching-ajax-results. – Brad M Mar 01 '13 at 18:10
  • Hmmm, thanks for the note Brad. This is indeed rather dumb on Apple's part if that's what they did. If it's only an issue with Apple mobile devices, I'd rather special-case for browsers for those devices to send back no-cache, rather than drop down to the lowest common denominator of not caching at all. Caching will mean a big win for my egress savings as well as significantly improve my back-end DB scalability. – Keith L Mar 01 '13 at 22:50
  • Furthermore, if the uer sees great performance on the desktop or other (e.g. Android) devices, then they will come to th conclusion that it is the Apple device that is slow, but not the service itself. Finally, did anyone know if Apple is keeping this behavior, or have they addressed/fixed this behavior in subsequent updates? Caching POST responses is bad enough, but caching and not providing a mechanism to ensure cache consistency is just unacceptable. – Keith L Mar 01 '13 at 22:54
1

I managed to finally figure this out. Turns out I need to make the following changes:

Client side jQuery:

  • Use "GET" instead of "POST" in my AJAX call. It appears the POSTs shouldn't be cached and rightfully-so.
  • Forget about setting "cache: true" in the AJAX call - this is irrelevant if you wanted ot use the browser cache. It only matters if you wanted to roll your own client caching system.

Server side:

  • Always send Last-Modified header
  • Always send "Cache-control: private, max-age=1"
  • Check "If-Modified-Since" header from client, if not modified, return 304 with no payload, else return 200 with result set.

Using the above logic I've set the browser cache to expire after 1 second, and will rely on the server to authoritatively decide whether a new catalog needs to be returned using the 304 code as appropriate. Seems to be working very well on IE.

Please note Brad's comment above about Apple mobile browsers misbehaving. Since only a fraction of my users will be using Apple mobile devices, I decided to keep the browser caching as the benefits are just too incredible to pass up, but try to special-case to force "no-cache" for Apple mobile browsers only.

Keith L
  • 33
  • 1
  • 7