function MakeRequest(url, timeout,
onCompleteCallback, onTimeoutCallback)
{
var completeCallback = onCompleteCallback;
var timeoutCallback = onTimeoutCallback;
var xmlHttp=createXMLHttpRequest();
if (xmlHttp)
{
xmlHttp.onreadystatechange = function()
{
if (xmlHttp.readyState == 4)
{
window.clearTimeout(timeoutId);
if (xmlHttp.status == 200 ||
xmlHttp.status == 304)
{
completeCallback(
xmlHttp.responseText);
}
}
};
xmlHttp.open("GET",url,true);
var timeoutId =
window.setTimeout(function()
{
if (callInProgress(xmlHttp))
{
xmlHttp.abort();
timeoutCallback('timeout');
}
} , timeout);
xmlHttp.send(null);
}
}
function callInProgress(xmlHttp)
{
switch ( xmlHttp.readyState )
{
case 1, 2, 3:
return true;
break;
// Case 4 and 0
default:
return false;
break;
}
}
function createXMLHttpRequest() {
if(window.XMLHttpRequest) {
try {
xmlHttpRequest = new XMLHttpRequest();
} catch(e) { return null; }
} else if(window.ActiveXObject) {
try {
xmlHttpRequest =
new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
try {
xmlHttpRequest =
new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) { return null; }
}
} else return null;
return xmlHttpRequest;
}
I then wanted to call a .Net HttpHandler, and lets just say for arguments sake that the htp handler looks like this
public class Handler : IHttpHandler
{
public void ProcessRequest (HttpContext context)
{
System.Threading.Thread.Sleep(6000);
context.Response.ContentType = "text/plain";
context.Response.Write(Guid.NewGuid().ToString());
}
public bool IsReusable
{
get
{
return false;
}
}
}
so the call from javascript would simply look something like this
MakeRequest(
'Handler.ashx?cookie=abcd&another=xyz',
20000, onRequestComplete,
onRequestTimeout);
function onRequestTimeout(response)
{
alert('timeout');
}
function onRequestComplete(response)
{
alert(response);
}
The problem as I found out through good old wikipedia relates to the internet explorers caching of the "GET" http command as described in this article on HMLHttpRequest.
As discussed in the article, there are a number of ways around this, switch to using POST or ensure that you switch the caching off in the http headers. I chose the former.
Hello Scott -
ReplyDeleteI'm an AJAXr from Phoenix Arizona. Have you ever seen inconsistent responses from the MS XMLHTTP object? I have run side-by-side tests of FF and IE on the same machine and often see the XMLHTTP object do the normal two pops of readystatechange with 1 and 1, then hang right there - never moving on to 2/3/4 - while the FF object just keeps chugging along...(ensuring network stability @ time of error) have you ever seen anything like that, and if so, what did you do to work around?
Thanks,
-EP
No, sorry ed, I haven't seen that one, although I do know that the FF and ie6 XMLHttpRequest objects do behave slightly differently, I just wish the W3C would hurry up and release a standard for it, then we could get back to situation normal, that is blaming Microsoft for not implementing the standard, (doesn't get us any further, just provides a vehicle for our rage). Having said that, it was Microsoft that first introduced XMLHttpRequest back in ie5.
ReplyDeleteMight be worth having a look at ie7, they have moved away from using the ActiveX control to a similar model to FF, they may have made other improvements too.
Cheers.
Thanks for the response Scott -
ReplyDeleteUnfortunately, the app I working on is for severeal clients and I have no say in the browser they are using. However, wrapping the object in a better timeout procedure as well as a couple little extra gotchas I worked through has made things a lot more stable. Just for your future ref, here are a couple things I did:
* Clear the onreadystatechange property BEFORE I call Abort - this handles an issue where the object would sometimes post a ready state of 4 when I abort()ed
* Reuse the object if it is FF et al, null and reinstantiate if it is IE
* Clear my timeout if I receive a readystate of 2 or greater - my problem was after the readystate 1 it would just hang - but timing wise, I got some times where the timeout popped (and aborted the request) while I was mid-process if I waited all the way to rs=4!
* Try the XMLHttpRequest first, msxml2 then the old IE object in that order - ie7 will use the new object (preferable) and the code degrades nicely into lesser versions of IE.
Cheers,
-EP
Thanks for this tip - my page was hanging on a ajax request in IE. I appended the URL with a random number to get around the HTTPGET caching issue.
ReplyDelete