Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

IE8 CORS support #934

Closed
jsteenkamp opened this issue May 4, 2012 · 14 comments
Closed

IE8 CORS support #934

jsteenkamp opened this issue May 4, 2012 · 14 comments

Comments

@jsteenkamp
Copy link

As per thread: https://groups.google.com/forum/#!searchin/angular/cors/angular/MoQ4pcn08io/eav59m8qzLkJ

@IgorMinar
Copy link
Contributor

http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/

in IE8 we need to use XDomainRequest:

var xdr = new XDomainRequest();
xdr.open("get", "http://www.nczonline.net/some_resource/");
xdr.onload = function(){
    //do something
};
xdr.send();

@jsteenkamp
Copy link
Author

Thanks - posted as "issue" in case you wanted to make IE8 support transparent in Angular. Not a major for me - so close if you wish.

@IgorMinar
Copy link
Contributor

it seems that XDomainRequest has some limitations and jquery is hesitant to include it in the core: http://bugs.jquery.com/ticket/8283

@pkozlowski-opensource
Copy link
Member

@IgorMinar do we want to support the XDomainRequest (IE8, 9) in the $http service? Based on @mhevery comments in #1047 it looks like no and given all the problems with XDomainRequest I would agree.

Maybe we should then close this issue and make it clear that XDomainRequest won't make it into $http?

@makeusabrew
Copy link

Hi all,

Sorry to dredge up an old thread; any further thoughts on this? Most of the group posts and other PRs just lead to dead ends.

@walski
Copy link

walski commented May 6, 2013

Has anyone ever tried to use flXHR to fix this? Running into the exact same problem 😢

@lanterndev
Copy link
Contributor

On 2012-05-07 @IgorMinar wrote:

it seems that XDomainRequest has some limitations and jquery is hesitant to include it in the core: http://bugs.jquery.com/ticket/8283

Since this comment, someone updated that ticket with:

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.

The XDR transport for jQuery is at: https://github.com/jaubourg/ajaxHooks/blob/master/src/xdr.js

Thought I'd post in case it's helpful to anyone watching this.

lanterndev added a commit to getlantern/www.getlantern.org that referenced this issue May 26, 2013
@walski
Copy link

walski commented May 28, 2013

I finally managed to get CORS working in IE8 and while this is definitively not for everyone here is a quick run-down on what I did:

In general I used flXHR as a Flash driven XHR drop-in replacement. We decided that it is ok to require Flash for our IE audience.

Here are the caveats I experienced during the implementation:

Flash does only support POST or GET methods

As our backend is written in Ruby the solution here was a small rack middleware that takes a FAKE-METHOD request header and then turns any POST request into the desired HTTP method.

Flash does not support empty bodies for POST methods

We built a small wrapper around flXHR that adds a dummy body whenever it was empty.

Flash does not allow you to send Authorization headers

This was a bummer as we used them for OAuth authentication. As a solution I enabled our backends to also read the token from a query param and the above mentioned flXHR wrapper just turned every Authorization header set into that query param.

IE or Flash seems to aggressively cache the AJAX responses

I just used the above mentioned wrapper to add a random seed as a query param to each request.

flXHR behaved differently on getAllResponseHeaders

It returned an array here but angular is expecting a string of all headers separated by \n.

Overall

This is far from a perfect solution but for us it was way easier than enabling JSONP across all our services. I'm happy to help anyone who runs into problems with flXHR as I spent quite some time now wrangling with it :)

The flXHR wrapper

Here is the wrapper I used to make flXHR work with angular. I just required the flXHR.js file and then this adaptor before loading angular. This is important as angular picks up the window.XMLHttpRequest on load and you can't really replace it later. Here is the raw code:

if (window.XDomainRequest !== undefined) {
  var originalXMLHttpRequest = window.originalXMLHttpRequest

  window.XMLHttpRequest = function() {
    flXHR = new flensed.flXHR();

    flXHR.autoUpdatePlayer = true;
    flXHR.xmlResponseText = false;
    flXHR.binaryResponseBody = true;

    var originalGetAllResponseHeaders = flXHR.getAllResponseHeaders;
    flXHR.getAllResponseHeaders = function() {
      return originalGetAllResponseHeaders().join("\n")
    };

    var originalOpen = flXHR.open;
    flXHR.open = function() {
      this.__angular_flxhr_request_headers = [];
      var method = arguments[0];
      if (method !== 'POST' && method !== 'GET') {
        flXHR.setRequestHeader('FAKE-METHOD', method)
        method = 'POST';
        arguments[0] = method;
      }
      this.__angular_flxhr_adaptor_http_method = method;
      this.__angular_flxhr_original_arguments = arguments;
    }

    var originalSetRequestHeader = flXHR.setRequestHeader;
    flXHR.setRequestHeader = function(header, value) {
      if (header === 'Authorization' && value !== undefined && value.match !== undefined && value.match(/^Bearer /)) {
        // Turn Authorization header into query param
        var newArguments = this.__angular_flxhr_original_arguments;
        var url = newArguments[1];
        if (url.match(/\?/)) {
          url = url + "&";
        } else {
          url = url + "?";
        }
        url = url + "oauth_token=" + value.replace(/^Bearer /, '');
        this.__angular_flxhr_original_arguments[1] = url;
      } else {
        this.__angular_flxhr_request_headers.push([header, value])
      }
    }

    var originalSend = flXHR.send;
    flXHR.send = function() {
      var newArguments = this.__angular_flxhr_original_arguments;
      var url = newArguments[1];
      if (url.match(/\?/)) {
        url = url + "&";
      } else {
        url = url + "?";
      }
      var randomSeed =  Math.floor((1 + Math.random()) * 0x1000000).toString(16) + (new Date().getTime().toString());
      url = url + "_id_random_seed=" + randomSeed;
      this.__angular_flxhr_original_arguments[1] = url;

      originalOpen.apply(this, this.__angular_flxhr_original_arguments);
      var headersToSet = this.__angular_flxhr_request_headers;
      for (var i = 0; i < headersToSet.length; i++) {
        originalSetRequestHeader.call(this, headersToSet[i][0], headersToSet[i][1]);
      }

      if (this.__angular_flxhr_adaptor_http_method === 'POST' && (arguments[0] === undefined || arguments[0] === null || arguments[0] === "")) {
        flXHR.setRequestHeader("Content-Type", "application/json");
        arguments[0] = '{}';
      }

      flXHR.setRequestHeader("Content-Type", "application/json");

      originalSend.apply(this, arguments);
    }

    return flXHR;
  }
}

@sudodoki
Copy link

sudodoki commented Sep 3, 2013

Used this snippet, but there's some problem with resolving relative paths, that're not starting with slash, i.e. : 'views/main.template.html' is resolved to '@hostname/views/main.template.html' instead '@hostname/@pathname/views/main.template.html', so in case you're using this, added

if (url.match(/^[^\/\s(http)]/)) {
  url = window.location.pathname + url;
}

at line 60-62 in "send" function.
Putting this here in case somebody else runs into this problem.

@IgorMinar
Copy link
Contributor

thanks @walski and @sudodoki

we are definitely not going to fix this in angular but your workaround might be useful for some folks.

@blaise-io
Copy link
Contributor

If someone was referred here by a search engine: I managed to implement CORS in IE9 and below using https://github.com/jpillora/xdomain, which is a straight-forward implement and it didn't require any modifications to Angular in our project.

@turbidwater
Copy link

I ended up here, and the solution I eventually used was the jsonp method of $http and using the Yahoo APIs. That got me past CORS issues in IE9
var crossdomainURL = 'http://query.yahooapis.com/v1/public/yql?q=';
crossdomainURL += encodeURIComponent('select * from rss where url="' + url + '"');
crossdomainURL += '&format=json&callback=JSON_CALLBACK';
$http.jsonp( crossdomainURL )
.success( function( data, status, headers, config ){
var resultAsJSON = data.query.results.item;
})
.error( function( data, status, headers, config ){
console.log( '!!! yahoo service error', data, status, headers, config );
});
}

@JogoShugh
Copy link

+1 on https://github.com/jpillora/xdomain. This really helped in a pinch!

@miukki
Copy link

miukki commented May 27, 2016

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests