Contact

Technology

Apr 12, 2017

CORS, Angular, and (*shudder*) IE9

Kash Cummings

Kash Cummings

CORS, Angular, and (*shudder*) IE9

IE9 has its own special way of handling cross-site requests, which required a unique solution.

Background

First, some information about our project to give you an idea of the problem we were facing. Our stack includes AngularJS for the front end with an ASP.NET WebAPI backend to serve our SPA data.

Our project is set up in a way that is becoming fairly typical, yet slightly different. We have multiple websites that sit at similar URLs (web.awesomesite1.comweb.awesomesite2.comweb.awesomesite3.com, etc.) and an API that all the websites point to. It sits at a subdomain of that URL (api.company.com).

Because the API sub-domain is considered different than the site making the resource request, we have to allow CORS (cross origin resource sharing) on our WebAPI server. The ASP.NET WebAPI framework handles this well after the request is made. However, our problem came from the front end before the request was even made.

 The Problem

CORS-Angular-IE9

Recently, our team came across an error that wasn’t very good at telling us what was wrong: “[object Error] Access is denied.” Fortunately for us, we knew the error only occurred in [*shudder*] IE9 and below, so a quick Googling revealed the underlying problem. As expected, underneath every Angular $http request is a creation of an XMLHttpRequest object to allow the handling of the request. This is how every browser handles http requests.

Except IE9 and below…

IE9 is special. IE9 has its own unique way for handling cross-site requests. It uses a XDomainRequest object instead. If you try using an XMLHttpRequest object to send a request that is across domains, you’ll get the “Access is denied” error from above.

The Solution

After searching many StackOverflow articles, reading blogs, and trying our own solution, we came across XDomain. XDomain was quick and worked well for us. There may be other solutions, but we found this to be the best at the time. XDomain solves a tricky problem in an incredibly clever way. However, it’s real strength is how simple it is to implement. We added a bit of logic on top of ours to ensure it only ran in case the typical XMLHttpRequest failed. 

  1. On our API server, we add a static html file called proxy.html that contains the following:

    • <!DOCTYPE HTML>

      <scriptsrc=”//master=”*”></script>

    • *Note: we have master="*" because we have multiple web.* domains that are trying to contact our API. Underneath the covers, this converts to a RegEx that you can be more specific about. See here for more information.

  2. In the index.html you use for your Angular app, include the following script before any other scripts. This script will try to make a request with the normal

     

    XMLHttpRequest

     object. If it fails, it will load the

     

    xdomain.min.js

     

    script and set the “slave” to the

     

    proxy.html

     

    page we put on our API server.

<script> try { var xhr = new XMLHttpRequest(); xhr.addEventListener('error', loadError); xhr.open("GET", "https://api.company.com/SmallApiCall?_" + Date.now()); xhr.send(); } catch (e) { loadError(e); } function loadError() { // Adding the script tag to the head as suggested before var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.type = 'text/javascript'; script.src = " //cdn.rawgit.com/jpillora/xdomain/0.7.4/dist/xdomain.min.js";   // Then bind the event to the callback function.        // There are several events for cross browser compatibility.        //script.onreadystatechange = callback; script.onload = callback;         // Fire the loading head.appendChild(script); function callback() { var helper = {}; helper["https://api.company.com"] = '/proxy.html'; xdomain.slaves(helper); } } </script>

And that’s it! This little library takes care of the rest in the most resourceful way.

  1. Your Angular app creates an

     

    <iframe>

     

    on the page whose source is your server’s

     

    proxy.html.

  2. Whenever you make any

     

    XMLHttpRequest

    , XDomain intercepts the message and uses the

     

    <iframe>

    ’s

     

    postMessage

     

    API to communicate inside the

     

    <iframe>

    .

  3. Since the

     

    <iframe>

    ’s domain is the API server, it is allowed to make the cross site requests to

     

    . It will make these requests and pass the responses back to wherever the call came from originally.

  4. Take that IE9.

Anybody can solve a problem, even a tricky one like this. XDomain shows a great amount of ingenuity, but the ease of implementation is what puts it over the top. At Credera, we build software that intersects “easy to use” and “solves tough problems,” so naturally we were drawn to this solution.

Head on over to the XDomain GitHub page for further reading and more information about the API.

Conversation Icon

Contact Us

Ready to achieve your vision? We're here to help.

We'd love to start a conversation. Fill out the form and we'll connect you with the right person.

Searching for a new career?

View job openings