views:

3174

answers:

8

I'm having a serious issue with Internet Explorer cachings results from a JQuery Ajax request.

I have header on my web page that get's updated everytime a users navigates to a new page. Once the page is loaded I do this

$.get("/game/getpuzzleinfo", null, function(data, status) {
    var content = "<h1>Wikipedia Maze</h1>";
    content += "<p class='endtopic'>Looking for <span><a title='Opens the topic you are looking for in a separate tab or window' href='" + data.EndTopicUrl + "' target='_blank'>" + data.EndTopic + "<a/></span></p>";
    content += "<p class='step'>Step <span>" + data.StepCount + "</span></p>";
    content += "<p class='level'>Level <span>" + data.PuzzleLevel.toString() + "</span></p>";
    content += "<p class='startover'><a href='/game/start/" + data.PuzzleId.toString() + "'>Start Over</a></p>";

    $("#wikiheader").append(content);

}, "json");

It just injects header info into the page. You can check it out by going to www.wikipediamaze.com and then logging in and starting a new puzzle.

In every browser I've tested (google, firefox, safari, ie) it works great EXCEPT in IE. Eveything get's injected just fine in IE THE FIRST TIME but after that it never even makes the call to "/game/getpuzzleinfo" it's like it has cached the results or something.

If I change the call to $.post("/game/getpuzzleinfo", ... IE picks it up just fine. But then Firefox quits working.

Can someone please shed some light on this as to why IE is chaching my $.get ajax calls?

Thanks~

UPDATE

Per the suggestion below, I've changed my ajax request to this which fixed my problem:

$.ajax({
    type: "GET",
    url: "/game/getpuzzleinfo",
    dataType: "json",
    cache: false,
    success: function(data) { ... }
});
+2  A: 

Gets are always cacheable. One strategy that may work is to edit the response header and tell the client to not cache the information or to expire the cache very soon.

marr75
That sounds like a good idea. How would I go about doing that?
Micah
That's a loaded question, depends on your server side code. See the wikipedia entry "List of HTTP headers" for a little guidance. Examples: Cache-Control: no-cache Expires: Thu, 01 Dec 1994 16:00:00 GMT Basically you need to append these response headers to your http response. It's fairly simple in ASP.NET, Ruby, and PHP. Just look up the server side language you're using + modify response headers.
marr75
Also, and this is not a criticism of Jquery at all (I love that library), the method of adding a random query string parameter is safe but impolite to the client (it can leave them holding onto items in cache that will never be used again).
marr75
+4  A: 

As marr75 mentioned, GET's are cached.

There are a couple of ways to combat this. Aside from modifying the response header, you can also append a randomly generated query string variable to the end of the targeted URL. This way, IE will think it is a different URL each time it is requested.

There are multiple ways to do this (such as using Math.random(), a variation on the date, etc).

Here's one way you can do it:

var oDate = new Date();
var sURL = "/game/getpuzzleinfo?randomSeed=" + oDate.getMilliseconds();
$.get(sURL, null, function(data, status) {
    // your work
});
Tom
+22  A: 

IE is notorious for its aggressive caching of Ajax responses. As you're using jQuery, you can set a global option:

$.ajaxSetup({
    cache: false
});

which will cause jQuery to add a random value to the request query string, thereby preventing IE from caching the response.

Note that if you have other Ajax calls going on where you do want caching, this will disable it for those too. In that case, switch to using the $.ajax() method and enable that option explicitly for the necessary requests.

See http://docs.jquery.com/Ajax/jQuery.ajaxSetup for more info.

NickFitz
You can also add a timestamp to the end of your urls. Not sure why jQuery doesn't go with this approach instead.
Eric Johnson
@Eric: that's what jQuery does internally - the "cache: false" option just tells it to do that.
NickFitz
+1  A: 

this is what i do for ajax calls:

var url = "/mypage.aspx";
// my other vars i want to add go here
url = url + "&sid=" + Math.random();
// make ajax call

it works pretty well for me.

Jason
+1  A: 

Jason, THANKS FOR YOUR REPLY!! I was spending a lot of time, and i was just not geting it! Your solution is clean and works 100%! (sorry for my bad english, i'm from PT :P

gld cld hlp! dd y knw yr nm wtht vwls s rmpt?
Jason
+1  A: 

I can't believe I have spent hours tracking this down by stepping through the jQuery library.

Came to the same conclusion that IE8 was caching the request (after stopping the webserver and realising that the XMLHttpRequest result had a 200 status code and the data). Hence I was then able to search in google for "ie8 caching ajax" and got here!

Thanks for the post :-)

Rob Bowall
Glad you figured it out. In the future this post would be better suited as a comment.
Micah
A: 

The answers here are very helpful for those who use jQuery or for some reason directly use the xmlHttpRequest object...

If you're using the auto-generated Microsoft service proxy its not as simple to solve.

The trick is to use Sys.Net.WebRequestManager.add_invokingRequest method in the event handler change the request url:

networkRequestEventArgs._webRequest._url = networkRequestEventArgs._webRequest._url + '&nocache=' + new Date().getMilliseconds(); 

I've blogged about this: http://yoavniran.wordpress.com/2010/04/27/ie-caching-ajax-results-how-to-fix/

poeticGeek
A: 

Just wrote a blog on this exact issue only using ExtJS (http://thecodeabode.blogspot.com/2010/10/cache-busting-ajax-requests-in-ie.html )

The problem was as I was using a specific url rewriting format I couldn't use conventional query string params (?param=value), so I had write the cache busting parameter as a posted variable instead..... I would have thought that using POST variables are a bit safer that GET, simply because a lot of MVC frameworks use the pattern

protocol://host/controller/action/param1/param2

and so the mapping of variable name to value is lost, and params are simply stacked... so when using a GET cache buster parameter

i.e. protocol://host/controller/action/param1/param2/no_cache122300201

no_cache122300201 can be mistaken for a $param3 parameter which could have a default value

i.e.

public function action($param1, $param2, $param3 = "default value") { //..// }

no chance of that happening with POSTED cache busters

Ben