In my foray into the depths of the browser known as Opera, I came across a rather unusual behavior the browser exhibits when using XMLHttpRequest. "unusual behavior" compared to my experience with IE and Firefox. What is this "unusual behavior"? The return of a different status code.
When using XMLHttpRequest, you generally want to check for two items in the onreadystatechange event handler. First, check the readyState property (bare with me, I'm putting this in for background info):
oReq.onreadystatechange = function () {
if (oReq.readyState == 4) {
//Proceed only when all data is received and available
}
};
A value of 4 signifies that the data has been received, and the complete data is available to use. At this stage, all you know is that you have data to work with. It may or may not be the data you requested. I say "may not" because an error may have been returned by the server; therefore, you need to check the HTTP status code:
oReq.onreadystatechange = function () {
if (oReq.readyState == 4) {
if (oReq.status == 200) {
//Everything's ok. Do something with the data.
}
}
};
If the status code is 200, then the request was successful and everything is ok… signifying that the data you have is the data you requested. It is at this step in which I've noticed different behavior in Opera… it doesn't always return a status code of 200. Sometimes you can get a code of 304.
Status code 304 signifies that the document has not been modified since the last time it was requested, and my research shows that this type of status is only returned when a conditional GET is sent to the server. But here's the kicker: Opera seems to be finicky on when it gets a 304 or a 200. My results are sporadic, at best.
So how can you work around this? You have three options (all with drawbacks).
1.) You can simply add a check for status code 304:
if (oReq.status == 200 || oReq.status == 304) {
}
This loads the data; however, it may be old data. It seems that Opera caches all data retrieved via XMLHttp (just like IE). The next solution solves this problem:
2.) Make sure that the request URI is unique for every request. This is easily done with a Date object:
var sUrl = "http://localhost/mydata.xml?uniqueId=" + (new Date()).getTime();
This approach solves the caching issue. The downside to this approach is logging: the server may log each individual request as a unique request. It is a unique URI, after all. (If you're like me, this is a problem).
3.) A server-side solution: set the Cache-Control header to no-cache. You can do this with .htaccess or in the server software itself (like IIS).
If you don't have the access to use .htaccess or change settings to the server, you can use a server-side technology like ASP.NET, PHP, Cold Fusion, etc. This, however, forces you to always serve your data files with your chosen tech. It may not be that big of a deal to some, but it does add more steps to the process.
Ahhh… the pain of cross-browser application development. The caching problem isn't all that new, as these solutions have been around for a while because of IE. The biggy was the different status code returned from the server. Live and learn, eh?
P.S. – I still don't like Opera.