6

I'm making an ajax request from an iframe that is injected onto every page via an IE plugin. I'm using IE's cross domain request because jQuery's ajax fails for IE. This works 75% of the time on IE8 & 9. The other 25%, the xdr.onload doesn't even fire.

The server php is doing its job...the log looks identical for when onload does and does not fire. Also, xdr.onerror doesn't fire either.

Any ideas?

        thisURL = "http://example.com/getmsg.php?cmd=getMessage&iid=ddeb2c1228&uurl=http%3A%2F%2Fwww.cnn.com%2F&t=" + Math.random(); 

        // Use Microsoft XDR
        var xdr = new XDomainRequest();
        xdr.open("GET", thisURL);
        xdr.onload = function() {
            // this is sometimes called, sometimes not in IE
            alert('INCONSISTENT ALERT');
            callback(xdr.responseText);
        };
        xdr.send();
Kyle Cureau
  • 19,028
  • 23
  • 75
  • 104
  • 1
    Just a random guess: you could try adding a nonsense parameter to the end of the URL to make sure the browser bypasses its cache ... I would try that myself if it were happening to me, but you may not be as interested in wasting time on complete guesses :-) – Pointy Mar 09 '11 at 18:17
  • 1
    ...or just use `POST` which will not get cached at all. Also, I'd bind `xdr.onerror = ` to see if that fires. Unfortunatly, there is no error description for XDR errors. Also, make sure `'Access-Control-Allow-Origin` header is set to `*` – jAndy Mar 09 '11 at 18:19
  • @Point, t is actually math.random...I've edited my answer. It's a good guess. This isn't be cached though – Kyle Cureau Mar 09 '11 at 18:35
  • @jAndy, `Access-Control-Origin` is set to `*` and xdr.onerror doesn't fire anything – Kyle Cureau Mar 09 '11 at 18:36
  • OK. As you can imagine I waste a lot of time on stuff like that :-) – Pointy Mar 09 '11 at 18:37
  • There's no particular reason this shouldn't work. How are you injecting your code? Do you have a repro that *does not* involve you injecting the content into a given page-- e.g. a fixed URL that reproduces the problem? – EricLaw Mar 17 '11 at 17:46
  • @EricLaw -MSFT...the fixed URL does reproduce the same problem. I'd post it here, but I'm trying to prevent it from going too public before I tighten up security issues. – Kyle Cureau Mar 17 '11 at 22:10
  • eh stupid question maybe... But have you tried to switch the position the `open` method and the `load` method? might be a parsing error... – Tokimon Mar 18 '11 at 11:40
  • @Tokimon, just tried that...didn't work. but thanks for the thought! – Kyle Cureau Mar 19 '11 at 20:35
  • have you tried checking the status of onreadystatechange? – mwilcox Mar 21 '11 at 21:57
  • onreadystatechange is for XHR, right? XDR is onload – Kyle Cureau Mar 22 '11 at 05:10

5 Answers5

9

I was having a very similar problem: XDomainRequests failing only some of the time, despite Fiddler showing all request and response headers being sent exactly as I intended. I had defined every event handler and the timeout property on these XDR objects, and none of the handlers were being called. The F12 developer tools showed the requests as aborted. Both GETs and POSTs could be aborted, to multiple different domains, but the first request always worked successfully.

Then I tried putting the calls to xdr.send in a timeout, like this:

setTimeout(function () {
    xdr.send();
}, 0);

and it worked. I have no idea why, but maybe this will be helpful to someone else.

sethobrien
  • 969
  • 7
  • 13
7

You're correct in naming the title here. The experience is rather inconsistent. Let's walk through it...

var xdr, err, res, foo, url;

xdr = new XDomainRequest();

err = function(){ alert("There was an error, operation aborted"); }
res = function(){ alert("Success! " + xdr.responseText); }
foo = function(){ return; }

url = "http://hello.com/here/is/the/url/?query=true&whatever=asd";

xdr.onerror = err;
xdr.ontimeout = foo;
xdr.onprogress = foo;
xdr.onload = res;
xdr.timeout = 5000;

xdr.open("get", url);
xdr.send(null);

The XDomainRequest object handles differently in every IE.

In IE9 -> the XDomainRequest object requires that all handles are given a method. Meaning, that handles like onerror, onload, ontimeout, and onprogress are all given something to do. Without defining a method for these handles then you'll get a network response of "operation aborted".

In IE7/8/9 -> the XDomainRequest is ASYNC by default. It will execute the code further down the stack regardless of the xdr object completing or not. Putting a setTimeout may be a solution but shouldnt be.

In this case, trigger an event and listen for the event before executing any further code. An example of this would be (in jquery)...

// call this method in xdr onload
$(document).trigger("xdr_complete");

// use this wrapper in code you want to execute after the complete of xdr
$(document).bind("xdr_complete", function(){ ... });

In IE7/IE8 you'll notice it working. IE7 and IE8 are rather "loose" in that they don't abort when there are missing method for the handles.

Erik5388
  • 2,171
  • 2
  • 20
  • 29
4

Found out the issue last minute. In my case I needed to specify a timeout value, even though the requests were not timing out. In order to properly debug an XDR issue I'd suggest the following code, with each alert telling you what's going on with your code. As I said, in my case it was a missing timeout declaration. But the code below should debug any XDR problems:

       var xdr = new XDomainRequest();
            if (xdr) {
                xdr.onerror = function () {
//                    alert('xdr onerror');
                };
                xdr.ontimeout = function () {
//                    alert('xdr ontimeout');
                };
                xdr.onprogress = function () {
//                    alert("XDR onprogress");
//                    alert("Got: " + xdr.responseText);
                };
                xdr.onload = function() {
//                    alert('onload' + xdr.responseText);
                    callback(xdr.responseText);
                };
                xdr.timeout = 5000;
                xdr.open("get", thisURL);
                xdr.send();
            } else {
//                alert('failed to create xdr');
            }
Kyle Cureau
  • 19,028
  • 23
  • 75
  • 104
  • 1
    Thanks - I missed the timeout too - and it seems to have a default value of 0! – Ben Bederson Aug 29 '12 at 02:36
  • In case it helps anyone, I just battled with IE9 XDR requests for my app and I found that it appears the timeout gets reset when you call the open() method (via manually constructing and inspecting a XDomainRequest object in the console). I was getting random failures until I set the timeout after calling the open method. (I still have it set before hand in case it matters). – Andrew Jan 22 '13 at 19:56
0

It is tough to give you a definitive answer here.

First, you should try using Fiddler to see if you are getting a network failure of some sort. It will help you to understand if the request has actually been made and the response from the server.

Second, and I don't know if this applies, we recently had a problem with cross domain on IE. The code worked fine in other browsers - Firefox, Safari and Chrome. The problem in that case turned out that the request was returning a 404 which was expected. Regardless, IE stopped all execution at that point, even our error handling of the 404 event was never fired. So, you could be getting some of the same here. Firefox, Safari, etc all let the script continue. If you are returning an error, you might want to have it return a success with an error value instead.

rvbyron
  • 179
  • 1
  • 4
0
  • First off, add an onerror handler to debug your stuff. Log them and see what exactly happens.
  • Second, your 'math.random' approach is flawed. A better option is to use new Date().getTime(), this will ensure you have a unique requests as time passes by.
  • Third, you could (probably should) use POST methods to bypass IE's obviously standards based behavior ( ;-) )
SchizoDuckie
  • 9,353
  • 6
  • 33
  • 40