Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails: best way to send cache headers with every ajax call

It's well known that Internet Explorer aggressively caches ajax calls whereas all the other browsers grab the data fresh every time. This is usually bad: I've never encountered a case where I want ajax to NOT contact the server. Firefox, Safari and the other browsers know this and don't cache ajax calls.

To prevent IE from caching, you have to do one of the following:

  • add a cache-busting token to the query string (like ?time=[timestamp])
  • send a HTTP response header that specifically forbids IE to cache the request
  • use an ajax POST instead of a GET

I much prefer setting a no-cache header. It's the correct way: it tells all browsers not to cache, which is exactly what you intend. The query string method fills up the browser's cache with stuff that'll never be retrieved, leaving less room for legitimate cache content. And the POST method is a corruption of HTTP: POSTs are for modifying data.

In Grails, what's the best way to automatically send a do-not-cache header for all ajax requests? I don't want to modify any controllers, so I'm thinking there's got to be a cool filter trick or something.

Thanks!

like image 280
Dean Moses Avatar asked May 13 '11 21:05

Dean Moses


1 Answers

Here's what I finally figured out. Most javascript libraries --including jQuery, YUI, Mootools and Prototype -- send the X-Requested-With: XmlHttpRequest header on every ajax request.

For any request that sends this header, you can send a response header back that tells it to not cache.

Below is a Grails filter that prevents caching of ajax requests that identify themselves with the X-Requested-With: XmlHttpRequest header:

// put this class in grails-app/config/
class AjaxFilters {
    def filters = {
        all(controller:'*', action:'*') {
            before = {
                if (request.getHeader('X-Requested-With')?.equals('XMLHttpRequest')) {
                    response.setHeader('Expires', '-1')
                }
            }
        }
    }
}

Some people prefer to use the Cache-Control: no-cache header instead of expires. Here's the difference:

  • Cache-Control: no-cache - absolutely NO caching
  • Expires: -1 - the browser "usually" contacts the Web server for updates to that page via a conditional If-Modified-Since request. However, the page remains in the disk cache and is used in appropriate situations without contacting the remote Web server, such as when the BACK and FORWARD buttons are used to access the navigation history or when the browser is in offline mode.

By adding this filter, you make Internet Explorer's caching consistent with what Firefox and Safari already do.

BTW, I've experienced the caching problem on IE8 and IE9. I assume the problem existed for IE7 and IE6 as well.

like image 159
Dean Moses Avatar answered Oct 13 '22 14:10

Dean Moses