Recently I’ve been working on a project, built in backbone.js, that is required to call a remote web service for its data. It also needs to work in Chrome, Firefox, and IE back to at least IE8.
I was sure this issue had been solved already. As it turns out, there are plenty of hacks out there to get it to work. There’s a great post on StackOverflow with some of your options:
Initially I implemented the flxhr option. Simple to get started - just drop some scripts on your page, check for jQuery.support.cors, and if the browser doesn’t support it, initialize the flxhr hack. This of course requires the user has Flash installed, but that’s not a huge deal. Ultimately I went looking for another option however because users were reporting some issues with things hanging in IE, and although I couldn’t pin it to the Flash proxy, it seemed possible it was causing it.
Instead of trying to implement another hack, I decided instead to try the native XDomainRequest support in Internet Explorer. This is what IE decided to use in IE8 and IE9 instead of XMLHttpRequest. I found this little script that overrides a function in jQuery to check for XDomainRequest support, and use that instead in those browsers.
Once again things were looking good. That is, until there was a server error and backbone showed a 404 not found error to the user instead of the proper error message. Looking at the code you’ll see on line 24 that if there’s an error in the ajax request, it has a hardcoded 404 error that it sends back to the jQuery callback. Well, surely I can fix that I thought. Maybe even patch it on Github. Unfortunately, as the Microsoft page on XDomainRequest says,
The document can respond to the error, but there is no way to determine the cause or nature of the error.
Sure enough, after plenty of testing, nothing I could do would give me a proper HTTP response from the server. Finally, the workaround:
I took the same xdr.js code, but modified it slightly. Unfortunately, I also had to modify the server-side code. What I do now is always return a 200 response to XDomainRequests from the server, but if there is an error, I send a JSON response back containing the true HTTP Status Code (400, 500, etc), and a Message field with the error. Lines 24-30 are what I changed to detect whether the response contains a JSON object with a StatusCode and Message field. If so, it overrides the actual status code and response sent back to jQuery.
This feels like a horrible hack, but the experience seems to have improved, I can continue using my REST routes, and we’re not relying on Flash anymore.