Bug Tracker

Opened 12 years ago

Closed 11 years ago

Last modified 10 years ago

#8283 closed enhancement (plugin)

Built-in support for XDomainRequest

Reported by: [email protected] Owned by:
Priority: low Milestone: 1.next
Component: ajax Version: 1.5
Keywords: 1.8-discuss Cc:
Blocked by: Blocking:

Description

Internet Explorer version 8 and up, in traditional Microsoft fashion, includes an alternative version of the XMLHttpRequest object named XDomainRequest; they share very similar interfaces, but the latter supports certain forms of cross-domain requests.

More information about it can be located here:
http://msdn.microsoft.com/en-us/library/cc288060(v=vs.85).aspx

It would be great if jQuery automatically used said object, where available, in ajax calls, when it detects an attempt to make a (non-JSONP) cross-domain request using Internet Explorer.

(Apologies in advance if this is not the right place for this issue or if it has already been dealt with; I've perused other tickets as well as the ajax support code to no avail. In particular, jQuery.support.cors does not seem to trigger the use of XDomainRequest.)

Thanks, Alvaro

Change History (36)

comment:1 Changed 12 years ago by jitter

Component: unfiledajax
Priority: undecidedlow
Resolution: duplicate
Status: newclosed

Thanks for taking the time to contribute to the jQuery project by writing an enhancement request.

There are currently no plans to support this in core and is better suited as a plugin.

But with the ajax rewrite that landed for 1.5 you should be able to write your own transport to handle non-JSONP cross-domain requests with IE.

Please checkout http://api.jquery.com/extending-ajax/ for more info.

If you happen to write a custom transport as jQuery plugin that uses XDomainRequest you might want to report back and add a link to it here so that others how happen to find this ticket can easily find it.

comment:2 Changed 12 years ago by jitter

Duplicate of #3342.

comment:3 Changed 12 years ago by anonymous

As an observation, this doesn't seem to be a duplicate of the #3342 to me. This would seem to be fodder for core work IMHO as it centers on mitigating browser-specific idiosyncrasies, but I'll respect this decision as better informed.

For reference and for the benefit of others trying to deal with IE's apparent non-support for Cross-Origin Resource Sharing via XMLHttpRequest (and their alternative: XDomainRequest) I'll offer this reference to a work-around which I found (not tested by me, yet).

http://graphicmaniacs.com/note/getting-a-cross-domain-json-with-jquery-in-internet-explorer-8-and-later/

comment:4 Changed 12 years ago by T.J. Crowder

Have to agree with @jitter and @anonymous: jQuery works around a wide variety of browser inconsistencies, that's probably about half its purpose (the other half being simplifying complex operations). This is a classic browser inconsistency: Chrome and Firefox support CORS via XMLHttpRequest; IE instead uses XDomainRequest. It makes no more sense for this to be a plug-in than it would for (say) handling IE's broken getAttribute function being a plug-in. Recommend reopening and scheduling for 1.6.1 or 1.6.2 (especially as jQuery now has the jqXHR concept).

Version 0, edited 12 years ago by T.J. Crowder (next)

comment:5 Changed 12 years ago by S. Legay

+1. IE still represents a very large number of users. It doesn't make any sense for jQuery core to start being picky about what browsers it wants to support.

True cross-domain Ajax seems to be possible in all major browsers, and should be fully supported by jQuery. There are many scenarios where jsonp just isn't good enough.

comment:6 Changed 12 years ago by Rick Waldron

Run this in IE6, when the result is "true" then it will be viable. I hate it as much as anyone, I promise.

http://jsfiddle.net/rwaldron/Lrx6q/

comment:8 Changed 12 years ago by Rick Waldron

Resolution: duplicate
Status: closedreopened

So, the real beauty of jaubourg's ajax rewrite is that adding a custom transport type is super easy. All you need to do is add a new file with your custom transport logic to the src/ajax directory and then add a line to the BASE_FILES in Makefile

Good luck and let us know if you need any help along the way!

comment:9 Changed 12 years ago by Rick Waldron

Resolution: patchwelcome
Status: reopenedclosed

comment:10 Changed 12 years ago by [email protected]

I was doing some review of the feasibility of using XDomainRequest, and while I haven't actually written any code, it seems like a lot of people have found that it is generally pretty broken in comparison to XMLHttpRequest - I'm still going to try and write some code but I'm not completely sure it is useful. I thought I'd post this note here for other people who are interested in cross domain XMLHttpRequest.

comment:11 Changed 12 years ago by [email protected]

Here is an example of the XDomainRequest transport we are using. Due to the poor error handling of XDomainRequest, we have support built into our backend which will return all errors as an xml document in the form of

<error response_code="xxx" message_key="abc">English Message</error>

Also, XDomainRequest only support text responses so that needs to be taken into account as well as is included below.

Please keep in mind that XDomainRequest adds the data as the text body of the request and this needs to be taken into account on the server side. We do detection of IE as the agent and take actions according in our request processing.

Please feel free to use the following code snippet to help you in any way, shape or form.

$.ajaxTransport( function( options, originalOptions, jqXHR ) {
    var xdr;

    return {
        send: function( _, completeCallback ) {
            xdr = new XDomainRequest();
            xdr.onload = function() {
                var responses = {
                    text: xdr.responseText
                };

                if (xdr.contentType.match(/\/xml/)){
                    // there is no responseXML in XDomainRequest, so we have to create it manually
                    var dom = new ActiveXObject('Microsoft.XMLDOM');
                    dom.async = false;
                    dom.loadXML(xdr.responseText);
                    responses.xml = dom;

                    if($(dom).children('error').length != 0) {
                        var $error = $(dom).find('error');
                        completeCallback(parseInt($error.attr('response_code')), $error.attr('message_key'), responses);
                    } else {
                        completeCallback(200, 'success', responses);
                    }

                } else {
                    completeCallback(200, 'success', responses); // we will assume that the status code is 200, XDomainRequest rejects all other successful status codes
                // see bug https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=334804
                }
            };
            xdr.onerror = xdr.ontimeout = function() {
                var responses = {
                    text: xdr.responseText
                };
                completeCallback(400, 'failed', responses);
            }

            xdr.open(options.type, options.url);
            if('POST' == options.type) {
                xdr.send(options.data);
            }
        },
        abort: function() {
            if(xdr) {
                xdr.abort();
            }
        }
    };
});

comment:12 Changed 12 years ago by [email protected]

My apologies. There's a typo in the above snippet. It should read:

xdr.open(options.type, options.url);
xdr.send(options.data);

The "if" isn't needed.

comment:15 Changed 11 years ago by ryanttb

If you only expect a text or json response, this version of the above works in IE9, even if you don't specify dataType: "json" in the ajax request:

$.ajaxTransport( function( options, originalOptions, jqXHR ) {
  var xdr;

  return {
    send: function( _, completeCallback ) {
      xdr = new XDomainRequest();
      xdr.onload = function() {
        if (xdr.contentType.match(/\/json/)) {
          options.dataTypes.push("json");
        }

        completeCallback(200, 'success', { text: xdr.responseText } );
      };
      xdr.onerror = xdr.ontimeout = function() {
        completeCallback(400, 'failed', { text: xdr.responseText } );
      }

      xdr.open(options.type, options.url);
      xdr.send(options.data);
    },
    abort: function() {
      if(xdr) {
        xdr.abort();
      }
    }
  };
});

comment:16 Changed 11 years ago by mattmanic

This is unbelievable that this is a known incompatibility for $.ajax for cross domain requests, and the core team are doing nothing about it. If it's as simple as adding a transport (which I'm trying do without luck), then why are the core team not including this for IE8+?

Guys, please address this is part of JQuery. Isn't that the point of JQuery, that it shields you from browser peculiarities?

comment:17 in reply to:  16 ; Changed 11 years ago by jaubourg

Replying to mattmanic:

This is unbelievable that this is a known incompatibility for $.ajax for cross domain requests, and the core team are doing nothing about it. If it's as simple as adding a transport (which I'm trying do without luck), then why are the core team not including this for IE8+?

Guys, please address this is part of JQuery. Isn't that the point of JQuery, that it shields you from browser peculiarities?

Have you tried this transport?

(and as a side note, you realize that jQuery simply can't "shield you" in IE6 and IE7 for instance)

Last edited 11 years ago by jaubourg (previous) (diff)

comment:18 in reply to:  17 Changed 11 years ago by anonymous

Replying to jaubourg:

Have you tried this transport?

This may be a dumb question, but is there a reason this isn't in jQuery core (yet)? Seems like you fulfilled the 'patchneeded' criterium, at least (potential review comments aside).

comment:20 Changed 11 years ago by steve_pax

This functionality should definitely be part of the jQuery core - avoiding browser inconsistencies is one of the huge strengths of jQuery!

comment:21 Changed 11 years ago by dmethvin

Resolution: patchwelcome
Status: closedreopened

comment:22 Changed 11 years ago by dmethvin

Resolution: plugin
Status: reopenedclosed

comment:23 Changed 11 years ago by dmethvin

Reopening for discussion, but in the meantime I'll close this as plugin since there is a solution available here:

https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js

Microsoft's XDR is not supported in IE6/7, and BTW the IE10 beta was just released with CORS support interfaces equivalent to other browsers.

comment:24 Changed 11 years ago by dmethvin

Keywords: 1.8-discuss added

comment:25 Changed 11 years ago by dmethvin

-1, Given the lame-duck status of XDR and its limitations I don't think this is worth the bytes. http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

comment:26 in reply to:  23 Changed 11 years ago by [email protected]

Replying to dmethvin:

Reopening for discussion, but in the meantime I'll close this as plugin since there is a solution available here:

https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js

This solution works for me in IE8, but in IE9 I see the request show up as "Aborted." Has anyone had luck with this workaround in IE9?

comment:27 Changed 11 years ago by dmethvin

#11202 is a duplicate of this ticket.

comment:29 Changed 11 years ago by anonymous

JQuery refuses to do CORS in IE9 without this support. IE9 gave me a "access denied" to let me know that using 1.4.4 ....not the case using 1.7.1. Not sure if that's poor debug/communication between IE9 or not. Either way, this was confusing to me for about an hour...

comment:30 Changed 11 years ago by [email protected]

xdr.js plugin from @jabourg with the IE9 fix:

@tlianza's xdr.js

comment:31 Changed 11 years ago by timMcKendrick

Concurring that it's absolutely insane for this not to be in the core. It's a massively useful patch that shouldn't have to be wedged in like this. Thanks for the code!

comment:32 Changed 11 years ago by Drizzt

@dmethvin: it'd still be helpful to have this in jQuery core, since not all users would (be able to) switch to IE10 the moment the final release is out. And having to use some plugin on _all_ projects, which rely on some AJAX functionality (with CORS) is simply not looking like a good solution. Maybe installing the transport conditionally would be an option?

So my vote is in favour of adding this to jQuery core.

comment:33 Changed 11 years ago by [email protected]

+1 for adding this to core. The plugin route is a pain in the rear end and requires adding a dependency on a plugin for code which must be distributed. Rather than simply saying "requires jQuery > x" distributing code requires a complete set of instructions for adding the plugin (or else bundling it with the distributed code, which presents a host or problems of it's own).

comment:37 Changed 11 years ago by anonymous

If JQuery still wants to be true to its values, this definitely sounds like something that should be in the core as soon as possible!

comment:38 Changed 11 years ago by Rick Waldron

@anonymous If it can't be done in all browsers that jQuery supports, then jQuery doesn't do it.

comment:39 Changed 11 years ago by dmethvin

To everyone asking for this to be in jQuery core: You understand that this will still not make IE8/9 cross-domain ajax support that works the same as the other browsers. Right? And you're willing to deal with all the special cases that contradict the documentation currently in $.ajax. Right? And it won't work in IE 6/7 which are still around. Right? And you're not going to file bugs against them, since we can't fix them. Right?

How many of you have actually used the XDomainRequest plugin mentioned above and understand its limitations?

comment:41 Changed 11 years ago by Jock Murphy <[email protected]…>

dmethvin, I would rather a jQuery that tries rather than one which does nothing. Yes there will be cases it can't handle... AND it might even be able to give an intelligible error messages in those cases. As opposed to, say, failing with no explanation and no clue to the user why it is failing. I lost hours to this today with no clue why it was an issue.

jQuery isn't a perfect shield against IE6, but it tries. Why can't this logic be applied to IE8 & 9 and XDR?

comment:42 Changed 11 years ago by dmethvin

It was a jQuery team member who tried and wrote the plugin available above. What is the problem with people using that again? You can get assistance with using the plugin on the forum if you need it. If the plugin needs to emit better error messages, perhaps you could work on that since it seems to be very important to you.

comment:43 Changed 10 years ago by dmethvin

PLEASE READ

Summary of the XDomainRequest issue:

  • IE 6, 7, 8, and 9 do not support XHR2 CORS. It is not possible to make generalized cross-domain requests in these browsers.
  • IE 8, 9 support an ActiveX control called XDomainRequest that only allows limited cross-domain requests compared to XHR2 CORS.
  • IE 10 supports XHR2 CORS.
  • jQuery does not include XDomainRequest support because there are numerous and serious limitations to XDR. Many reasonable $.ajax requests would fail, including any cross-domain request made on IE6 and IE7 which are otherwise supported by jQuery. Developrers would be confused that their content types and headers were ignored, or that IE8 users couldn't use XDR if the user was using InPrivate browsing for example.
  • Even the crippled XDR can be useful if it is used by a knowledgeable developer. A jQuery team member has made an XDR ajax transport available. You must be aware of XDR limitations by reading this blog post or ask someone who has dealt with XDR problems and can mentor you through its successful use.
  • For further help and other solutions, ask on the jQuery Forum, StackOverflow, or search "jQuery xdr transport". Requests posted here will be deleted.

comment:44 Changed 10 years ago by [email protected]

For anyone getting a 404 on the xdr.js plugin mentioned above, it has been moved here:

https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

Note: See TracTickets for help on using tickets.