I'm currently on parental leave till September 1st. Until then, I will not be available to read comments, e-mails, tweets and Facebook messages.

If you are interested in my writings, please subscribe to my RSS feed and follow me on Twitter.

Weird XMLHttpRequest error in IE – just one call allowed

Recently in a project I’ve been working on, I stumbled across something that I haven’t seen before: one AJAX call was possible to make in the web page, but after that it stopped working.

To give you some context: this (naturally) only occurred in Internet Explorer, both with the native XMLHttpRequest in IE 7 and an ActiveXObject for IE 6. A sidenote, but if anyone’s wondering: I use a try...catch statement to find the supported ActiveXObject in the visiting web browser:


try {
    this.xmlHttp = new ActiveXObject("Msxml2.XMLHTTP.4.0");
}
catch(e){
    try {
        this.xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
    }
    catch(e){
        try {
            this.xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch(e){
            this.xmlHttp = null;
        }
    }
}

My unsuccessful approach

My initial approach was to create the object once, and then use it for the consecutive calls when needed. This would be opposed to creating an object, making the calls and then deleting the object for each AJAX call. Silly little me thought this would be good for performance, and basically just refrain from superfluous object creation. But, apparently, the call just “stuck” in IE after it was completed, preventing the possibility to make any more calls.

A cut down version of the (originally object-oriented and fancy ;-) ) code was:


var xmlHttp = null;
/*
    This function was called as soon as the page
    had loaded, so xmlHttp was always available
*/
function createXMLHttpRequest(){
    if(typeof XMLHttpRequest != "undefined"){
        xmlHttp = new XMLHttpRequest();
    }
    else if(typeof window.ActiveXObject != "undefined"){
        try {
            xmlHttp = new ActiveXObject("Msxml2.XMLHTTP.4.0");
        }
        catch(e){
            try {
                xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
            }
            catch(e){
                try {
                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
                catch(e){
                    xmlHttp = null;
                }
            }
        }
    }
}

function getTheContent(url){
	xmlHttp.abort(); // Tried both with and without this
	xmlHttp.onreadystatechange = contentIsReady;
	xmlHttp.open("GET", url, true);
	xmlHttp.send(null);
}

function contentIsReady(){
    if(xmlHttp && xmlHttp.readyState == 4){
        // Do some magic
    }
}

The one that worked

This is basically the same code as above, with the exception that the XMLHttpRequest object is created each time, and discarded once the call is done.


function createXMLHttpRequest(){
    var xmlHttp = null;
    if(typeof XMLHttpRequest != "undefined"){
        xmlHttp = new XMLHttpRequest();
    }
    else if(typeof window.ActiveXObject != "undefined"){
        try {
            xmlHttp = new ActiveXObject("Msxml2.XMLHTTP.4.0");
        }
        catch(e){
            try {
                xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
            }
            catch(e){
                try {
                    xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
                catch(e){
                    xmlHttp = null;
                }
            }
        }
    }
    return xmlHttp;
}

function getTheContent(url){
    if(xmlHttp){
        xmlHttp.abort();
    }
    // Create the object each time a call is about to be made
    if(createXMLHttpRequest()){
	xmlHttp.onreadystatechange = contentIsReady;
	xmlHttp.open("GET", url, true);
	xmlHttp.send(null);
    }
}

function contentIsReady(){
    if(xmlHttp && xmlHttp.readyState == 4){
        // Do some magic

        // Delete the object after the call is done
        xmlHttp = null;
    }
}

Any ides why it doesn’t work?

With those examples I have to ask you: do you have any ideas why it wouldn’t work with a single object creation? How come one call is ok, but it then just stops working?

28 Comments/Reactions

  • #1 Sjors Rijsdam
    April 4th, 2007 at 9:12

    I did a Google Maps mashup about 1,5 years ago, you know, when they we’re still hot. For that I used a few global variabels, one of which was a xmlHttp object. Since I didn’t know much about JS at the time I made the requests synchronous to avoid scope issues. It worked like a charm.

  • #2 Ash Searle
    April 4th, 2007 at 10:46

    Total guess… but I notice you’re setting onreadystatechange before calling open (which is different to the way things are normally done: e.g. prototype library, my own code, etc.)

    I don’t suppose setting the handler after calling open fixes things does it?

  • #3 Dave O’Brien
    April 4th, 2007 at 11:22

    Ash Searle’s right, IE resets the object when you call open() so you need to have your onreadystatechange after it. On a side note, you really should check your code before posting (I’m referring to getTheContent() ).

  • #4 Robert Nyman - author
    April 4th, 2007 at 13:15

    Sjors,

    I know that when making synchronous requests, there is (or at least was) a problem with Firefox and the onreadystate event.

    Ash,

    Interesting. I know that the onreadystatechange event needs to be applied before the send event, but then not necessarily before the open method.

    Thanks! I’ll try it out!

    Dave,

    Thanks for confirming that.

    …you really should check your code before posting—

    Aww. I was trying to blog on a bouncy train. I have no idea where the extra indentation and erroneous } came from… ;-)

    Anyway, I’ve updated the post with correct code.

  • #5 André
    April 4th, 2007 at 13:19

    I know I’ve bumped into this problem with a project of mine but didn’t find any solution. Could that be it? So it means that you only open() once? Have to try it myself. Thanks for the tip, Ash.

  • #6 myf
    April 4th, 2007 at 15:31

    (totally nitpickerish off-topic; feel free to delete it)

    I would never use any formatting like that (…)

    “Huh?!” Is it really four-spaces indent I see in your examples? :)

  • #7 Robert Nyman - author
    April 4th, 2007 at 15:43

    myf,

    Ha ha! :-D
    Actually, it’s quite interesting. The pre-formatted source code is indeed indented with tabs, but when saving/publishing a post with WordPress, it replaces the tabs with spaces.

    Man, that is a hawk eye thing to notice something like that!

  • #8 Remy Sharp
    April 5th, 2007 at 9:49

    Hi – have you tried cache busting? I was building a “live price” system and found that IE would show the price changes once and then the requests wouldn’t continue.

    I changed the URL and appended Math.random() and it fixed the problem outright.

  • #9 Robert Nyman - author
    April 5th, 2007 at 13:43

    Remy,

    Interesting approach. If the problem persists, it’s definitely something to try.

  • #10 Ash Searle
    April 5th, 2007 at 16:48

    Remy / Robert,
    If you find IE’s using cached XHR responses, you’ve got a couple of things to looks at before resorting to brute-force timestamps:
    1) Should you be using "POST" instead of "GET"? (does the XHR request cause a permanent change on the server? If so, you should be using "POST" anyway.)
    2) Is the server setting appropriate Expires and Cache-Control headers on the XHR response?

  • #11 Robert Nyman - author
    April 5th, 2007 at 20:04

    Ash,

    Very good points! Thank you for contributing!

  • #12 Nick Fitzsimons
    April 7th, 2007 at 15:15

    It’s definitely the fact that you assign the onreadystatechange handler before the open method invocation. This was mentioned a while ago on the IE Team’s blog:

    Xmlhttp.open has a “reset” semantic so the second open() call on the same object will abort the previous connection, disconnect previous event handler, and reset the object.

    (This means that you don’t need to invoke the abort method, either.)

  • #13 Robert Nyman - author
    April 7th, 2007 at 21:29

    Nick,

    Thanks for the info! However, the abort method should still be important for other web browsers, right? To stop the current connection and start a new one.

  • #14 Nick Fitzsimons
    April 9th, 2007 at 18:19

    Robert,
    The W3C Draft Spec for the open() method ofXMLHttpRequest states that:

    Invoking this method must initialize the object by remembering the method, url, async (defaulting to true if omitted), user (defaulting to null if omitted), and password (defaulting to null if omitted) arguments, setting the state to open, resetting the responseText, responseXML, status, and statusText attributes to their initial values, and resetting the list of request headers.

    In addition, when the state is not uninitialized, all members of the object with the exception of onreadystate must be set to their initial values and user agents must behave as if abort() was invoked.

    My rough and ready tests indicate that this isn’t necessarily how things work in the wild though… Firefox in particular seems to get a little upset if abort() isn’t invoked, but gets upset a different way if it is :-(

  • #15 Robert Nyman - author
    April 9th, 2007 at 21:42

    Nick,

    Hmm, interesting. When it comes to Firefox and the abort method (a problem I’ve been facing as today, actually), the approach and description by Peter-Paul Koch described in XMLHTTP notes: abort() and Mozilla bug solves it. :-)

  • #16 John Himmelman
    July 27th, 2007 at 14:03

    Thanks! This blog entry saved me a good hour of debugging! :)

  • #17 Robert Nyman - author
    July 27th, 2007 at 14:05

    John,

    I’m glad it helped!

  • #18 royc
    August 28th, 2007 at 12:24

    i think the we dont need such complication if the a slight change is made:

    getTheContent()
    {
    createXMLHttpRequest();
    blah..
    blah..
    blah..
    }

  • #19 LongStone
    October 2nd, 2007 at 21:49

    Seems like the IE cache issue @ first glance.
    It will cache EVERYTHING in the GET scope, setting timeouts/headers etc doesn’t matter.

    I just set the “ID” of may AJAX request (I’m using conio which still uses the initial JSON-RPC spec) to a random number (could append to ID if you’re actually using it for something)

  • #20 Robert Nyman - author
    October 2nd, 2007 at 22:37

    LongStone,

    At the end, it was the order of the code that was the culprit.

  • #21 Gurdi
    October 15th, 2007 at 20:21

    Thanks Ash and Dale! Thanks Robert!

    I had the same problem, IE7 allowed only one request and then XHR “died”. Solution really was to set XHR.onreadystatechange after calling XHR.open();

    Cheers!

  • #22 Robert Nyman - author
    October 16th, 2007 at 11:56

    Gurdi,

    I’m glad it helped!

  • #23 Nik
    December 15th, 2007 at 9:13

    I have tried everything that you guys have mentioned above … but am still getting “permission Denied” error beyond the first XHR Call
    :(

  • #24 Robert Nyman - author
    December 17th, 2007 at 10:13

    Nik,

    The reason might that you try to run files iles locally, which won’t work in Internet Explorer. Makes sure they’re on a server and things should work fine for you (I hope).

  • #25 Charles Chen
    June 20th, 2008 at 21:35

    I’m experiencing this issue as well with IE7. I tried both prototype and jQuery in an attempt to see if it was isolated to prototype.

    Still haven’t figured this one out yet and it’s quite puzzling (especially since Microsoft’s AJAX libraries with ASP.NET AJAX work fine…).

    The odd thing is that it all works fine if I’m running Fiddler (which kind of makes me wonder whether it’s a caching issue). As soon as I shut off Fiddler, I get 400/”Bad Request” errors.

    In order to inspect the HTTP request, I had to use WireShark on the server (since Fiddler on the client was causing it to work for every request). It turns out that the requests are drastically different on successful attempts and failed attempts. Notably, even though the requests are identical, the content length is always 0 on failed requests.

    Here is a failed request:


    POST /FirstPoint.Common.Services.UserDriven/UserDrivenService/GetRoutes HTTP/1.1
    Accept: text/javascript, text/html, application/xml, text/xml, */*
    Accept-Language: en-us
    x-prototype-version: 1.6.0.2
    Referer: http://zorch6:2345/_layouts/FirstPointUserDrivenRoutes/Default.aspx
    x-requested-with: XMLHttpRequest
    Content-Type: application/json; charset=UTF-8
    UA-CPU: x86
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; WOW64; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; InfoPath.2; MS-RTC LM 8; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
    Host: zorch6:2345
    Content-Length: 0
    Connection: Keep-Alive
    Cache-Control: no-cache
    Cookie: MSOWebPartPage_AnonymousAccessCookie=2345; WSS_KeepSessionAuthenticated=2345; previousLoggedInAs=; loginAsDifferentAttemptCount=
    Authorization: NTLM TlRMTVNTUAABAAAAB7IIogkACQA0AAAADAAMACgAAAAFAs4OAAAAD0NIQVJMRVMtUVVBRFdPUktHUk9VUA==

    Here is a successful request:

    POST /FirstPoint.Common.Services.UserDriven/UserDrivenService/GetRoutes HTTP/1.1
    Accept: text/javascript, text/html, application/xml, text/xml, */*
    Accept-Language: en-us
    x-prototype-version: 1.6.0.2
    Referer: http://zorch6:2345/_layouts/FirstPointUserDrivenRoutes/Default.aspx
    x-requested-with: XMLHttpRequest
    Content-Type: application/json; charset=UTF-8
    UA-CPU: x86
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; WOW64; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; InfoPath.2; MS-RTC LM 8; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
    Host: zorch6:2345
    Content-Length: 16
    Proxy-Connection: Keep-Alive
    Pragma: no-cache
    Cookie: MSOWebPartPage_AnonymousAccessCookie=2345; WSS_KeepSessionAuthenticated=2345; previousLoggedInAs=; loginAsDifferentAttemptCount=

    And here is a request from FF (in which the AJAX request works flawlessly):

    POST /FirstPoint.Common.Services.UserDriven/UserDrivenService/GetRoutes HTTP/1.1
    Accept: text/javascript, text/html, application/xml, text/xml, */*
    Accept-Language: en-us
    x-prototype-version: 1.6.0.2
    Referer: http://zorch6:2345/_layouts/FirstPointUserDrivenRoutes/Default.aspx
    x-requested-with: XMLHttpRequest
    Content-Type: application/json; charset=UTF-8
    UA-CPU: x86
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; WOW64; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; InfoPath.2; MS-RTC LM 8; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
    Host: zorch6:2345
    Content-Length: 16
    Proxy-Connection: Keep-Alive
    Pragma: no-cache
    Cookie: MSOWebPartPage_AnonymousAccessCookie=2345; WSS_KeepSessionAuthenticated=2345; previousLoggedInAs=; loginAsDifferentAttemptCount=

    Prototype has the correct ordering of calls to XHR to initiate the request, so I’m baffled by what could be causing this issue.

    Any thoughts would be appreciated.

    - Chuck

  • #26 Brian Giedt
    October 17th, 2008 at 21:15

    Charles,

    I’m having the same problem as you and think I have some idea about what’s happening but not the cause.

    Your failed request includes a “Authorization: NTLM …” line and I’ll be that the payload of your request never made it to the server. If you aren’t sending anything with the send() method, then you’re probably not noticing it.

    I believe that the browser is attempting to send a request to authenticate the request before it actually bothers to post the data your requesting.

    At least that’s what I’m seeing in my code when I look at it with Fiddler.

  • #27 spentamanyu
    July 6th, 2010 at 1:56

    For those who reached this paged from google with that issue, the one with the crappy IE8 working only when you refresh the page. I solved (find the solution in antoher page) moving the meta tag

    just afer the tag. So it must be this way

    and not this other way arround (next example is the one who troubles)

    Hope its helpfull to someone.

  • #28 spentamanyu
    July 6th, 2010 at 23:30

    Damn it:

    proper way; html,head,title,metatag,script
    wrong way; html. head. title.script. metatag

Write a comment

Twitter reactions

Share your thoughts:

HTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> . If you want to display code examples, please remember to write &lt; for < and &gt; for >.

Comment preview