Search
Lori MacVittie - Two Different Socks
You are here: DevCentral > Weblogs

posted on Thursday, June 26, 2008 4:41 AM

A few weeks ago, as developers are wont to do, I rewrote our online gameroom. Version 1 was getting crusty, and I'd written all the AJAX handlers manually and wanted to clean up the code by using Prototype and Script.aculo.us. You may recall we discussed using these tools to build a Web 2.0 interface to iControl.

So I rewrote it and was pretty pleased with myself. Until one of our players asked why it wasn't working in Internet Explorer (IE). Now Version 1 hadn't worked in IE either, but because I have a captive set of users I ignored the problem and forced them all to use FireFox instead. But this player's wife will be joining us soon and she's legally blind. She uses a reader to get around the Internet and as luck would have it, the reader only works with IE.

So I started digging into the problem. I had thought it was my code (silly me), and thus moving to prototype would solve the problem. No such luck. Everything but the periodically updated pieces of the application worked fine. The real-time updating components? Broken in IE. 

I looked around and found this very interesting article on Wikipedia regarding known problems with IE and XMLHTTPRequest, the core of AJAX.

From the Wikipedia article

Most of the implementations also realize HTTP caching. Internet Explorer and Firefox do, but there is a difference in how and when the cached data is revalidated. Firefox revalidates the cached response every time the page is refreshed, issuing an "If-Modified-Since" header with value set to the value of the "Last-Modified" header of the cached response.

Internet Explorer does so only if the cached response is expired (i.e., after the date of received "Expires" header).

Basically, the problem lies with IE's caching mechanisms. So if you were trying to build an AJAX application with a real-time updating component and it didn't seem to work in IE, now you may know why that is.

There are workarounds:

  1. Modify the AJAX call (within the client-side script) to check the response and, if necessary, make a second call with a Date value in the past to force the call to the server.
  2. Append a unique query string to the call, for example appending a timestamp. This makes the URI unique, ensuring it won't be in the cache and forcing IE to call out to the server to get it. 
  3. Change all requests to use POST instead of GET.
  4. Force the "Expires" header to be set in the past (much in the way we expire cookies programmatically). Setting cache control headers may also help force IE to act according to expectations.

I used option #3, because it was a simple, quick fix for me to search the single script using Ajax.PeriodicalUpdater and automatically change all the GETs to POSTs. That may not feasible for everyone, hence the other available options.

Option #4 could easily be achieved using iRules, and could be coded such that only requests sent via IE were modified. In fact, Joe has a great post on how to prevent caching on specific file types that can be easily modified to solve the problem with IE.

First we want to know if the browser is IE, and if so, we want to modify the caching behavior on the response. Don't forget that IE7 is using a slightly different User-Agent header than previous versions of IE. Don't look for specific versions, just try to determine if the browser is a version of IE.

when HTTP_REQUEST {
if {[string tolower [HTTP::header "User-Agent"]] contains "msie"} {
set foundmatch 1
}
}
when HTTP_RESPONSE {
if {$foundmatch == 1} {
HTTP::header replace Cache-Control no-cache
HTTP::header replace Pragma no-cache
HTTP::header replace Expires -1
}
}

You could also use an iRule to accomplish #3 dynamically, changing the code only for IE browsers instead of all browsers. This requires a bit more work as you'll have to search through the payload for 'GET' and replace it with 'POST'. It's a good idea to make the search string as specific as possible to ensure that only the HTTP methods are replaced in the Ajax.PeriodicalUpdater calls and not everyplace the letters may appear in the document, hence the inclusion of the quotes around the methods.

Happy Coding!

Follow me on Twitter


Imbibing: Coffee



Feedback

6/26/2008 6:46 AM
Gravatar I think your HTTP_REQUEST irule has a typo. You probably want to either:

change 'tolower' to 'toupper'
or
change "MSIE' to "msie'

Otherwise your if will never match, as the user-agent will be converted to all lowercase and the string you're looking for is all uppercase. :)
Andy Herrman
6/26/2008 6:49 AM
Gravatar Andy,

Good catch, thanks! I updated (fixed) the iRule so case sensitivity is correct.

Lori
Lori MacVittie
6/26/2008 10:16 AM
Gravatar You'll also likely want to make sure you're re-setting foundmatch to 0 either at the beginning of the HTTP_REQUEST event or the end of the HTTP_RESPONSE event to avoid false positives.

I know that theoretically all the requests in a given connection will be coming from the same user agent, and thus it's more of an academic issue, but still, it just seems proper, so I thought I'd point it out. ;)

#Colin
Colin
12/17/2008 8:29 AM
Gravatar Doesn't seem to work:

01070151:3: Rule [ie_force_expire_header] error:
line 1: [wrong # args] [when HTTP_REQUEST {
if [string tolower [HTTP::header "User-Agent"]] contains "msie"} {
set foundmatch 1
}]
line 6: [command is not valid in the current scope] [}]

Any ideas?
Josh
12/17/2008 8:31 AM
Gravatar @Josh

Looks like I have a typo in the code (will fix after replying to you):

if [string tolower [HTTP::header "User-Agent"]] contains "msie"} {

Is missing an opening brace... should be:

if {[string tolower [HTTP::header "User-Agent"]] contains "msie"} {


Lori MacVittie
12/17/2008 8:53 AM
Gravatar Fixed my expiring headers problem in IE6! Thanks!
Josh
7/30/2009 8:47 PM
Gravatar Thanks a lot!! This really saves me from re-encoding everything!
Elmo
9/15/2009 5:23 AM
Gravatar I am using Ajax, I am not receiving Status completion on Internet explorer, even though process is completed. But "Done" is updated on the status bar.
Please some one help me to resolve this.
Pramod.S
9/15/2009 10:01 AM
Gravatar @Pramod

Couple questions:

1. You're using "AJAX". Are you using XAJAX? Prototype? Dojo? Custom code?

2. Have you used a tool like Firebug or HTTPWatch or HTTP Fox to verify that the response is indeed making it back to the browser?

3. I assume by "Status completion" you mean the callback that fires when an HTTP 200 response is received is not executing? Are you receiving an HTTP 200 OK or perhaps the reason Status completion is not being received is because there's a problem with the call and some other HTTP response is being returned?

Can you provide a bit more detail regarding the problem?

Thanks
Lori
Lori MacVittie
3/26/2010 7:14 AM
Gravatar Hello

I an using Ajax with JQuery. The Response is a text string containing HTML content. And I'm trying to dynamically build the a HTML section in the page. The section has tables,tr,td tags.
I'm using .innerHtml to set the response in a div section.This is working in FF. But in IE it is throwing an unknown runtime exception.
Sankar
4/1/2010 3:57 AM
Gravatar That's awesome dude! Spent a whole DAY pondering and swimming in an ocean of references over variable scope in JS. Til I met you, it was love on first sight.

It Worked to change mootools Request.JSON GET req. to a POST req.

Cheers mate.
Johan Hultgren
11/11/2010 10:33 PM
Gravatar Hi I have this code, its not working on any version of IE, can u plz tell me where I m wrong? Thanks

if (window.XMLHttpRequest)
{
xmlhttp = new XMLHttpRequest();
}

else if(window.ActiveXObject)
{
try
{
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}

catch (e)
{
xmlhttp = false;
}
}
}

xmlhttp.onreadystatechange=function()
{
if(xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById('spinner').style.display = "none";
document.getElementById("pickZone").innerHTML=xmlhttp.responseText;
}
}

xmlhttp.open("GET","getPickZone.jsp?q="+str,true);
xmlhttp.send();
Harsh Vardhan Mehrotra
12/19/2010 10:30 PM
Gravatar how to build request on ie.. i've this code ... its not working..ie displays error in page it could not create object request
function getXMLHTTP() { //fuction to return the xml http object
var xmlhttp=false;
try{
xmlhttp=new XMLHttpRequest();
}
catch(e) {
try{
xmlhttp= new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e){
try{
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e1){
if (!xmlhttp && window.createRequest) {
try {
xmlhttp = window.createRequest();
} catch (e) {
xmlhttp=false;
}
}
}
}
}

return xmlhttp;
}
var req = getXMLHTTP();
var strURL="http://mypage.php?q=1";
if (req) {

req.open("GET", strURL, true);
req.send(null);
}
BALA
3/24/2011 10:41 AM
Gravatar Would the edit below do just the opposite? We are on 10.2.1 and IE7 is not caching. Firefox does, however, most users are stuck with IE7 and the load times are 5-10x slower than Firefox or IE8.
How would setting Cache-Control to private be different?


when HTTP_REQUEST {
if {[string tolower [HTTP::header "User-Agent"]] contains "msie"} {
set foundmatch 1
}

}

when HTTP_RESPONSE {
if {$foundmatch == 1} {
HTTP::header replace Cache-Control public
HTTP::header replace Pragma public
HTTP::header replace Expires -1
}
}

Kofi Merritt
4/26/2011 7:42 PM
Gravatar thank! good good
A_C
4/27/2011 4:10 AM
Gravatar Many thanks for article!

I spend over 5 hours to find out why shitty IE use buffor for my AJAX?!

"Change all requests to use POST instead of GET." <- that helped!

Greetings form Poland
Przemysław 'th3mon' Szelenberger :-)
Przemysław 'th3mon' Szelenberger
7/13/2011 2:40 AM
Gravatar Thank's alot

I've used your #2 solution, adding a counter at the end of my URL
Steven
11/16/2011 5:13 AM
Gravatar Thanks, your solution #2 helped me :)
Thanks Steven as well, i used your solution.
Ubaid Raja
12/1/2011 2:22 AM
Gravatar Another solution if you use jQuery :
Add that to your request
$.ajax({
url: "http://url",
cache: false,
});
Erwan
12/20/2011 7:47 AM
Gravatar #2 suggestion saved the day!!
Jacob

Let Me Know What You Think


Please use the form below if you have any comments, questions, or suggestions.

Title:
 
Name:
 
Email: (so we can show your gravatar)
Website:
Comment: Allowed tags: blockquote, a, strong, em, p, u, strike, super, sub, code
 
Please add 6 and 1 and type the answer here:

Blog Stats

Posts:979
Comments:1685
Stories:0
Trackbacks:583
  

Image Galleries

  

Application Delivery

  

Cloud Computing

  

Random

  

Security

  

Chat Catcher

82,243 Members in 102 Countries and Growing!

Join DevCentral Today!

About DevCentral

DevCentral has been a successful, thriving community for many years. We have always strived to bring you the best technical documentation, discussion forums, blogs, media and much more that we can.

So dive in, get familiar with DevCentral. We hope you like it, we hope it makes your job easier, and lets you get that much more power out of the community. To learn more, make sure to check out the Getting Started section. And if you have any problems, or think something could be easier to use, drop us a line to let us know.

Got It !

We've received your comment and transmitted it directly to DevCentral HQ.

Thanks for taking time to let us know what's on your mind. At DevCentral | Community Matters!

Get In Touch With Us

Have questions, suggestions or just want to get something off your chest?

Use our handy form below to Direct Connect with DevCentral Mission Control.

Send Us Feedback       or