IE CORS support in jQuery
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:
http://stackoverflow.com/questions/3385404/ie8-xss-jquery-problem
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.
https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js
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:
https://gist.github.com/2655118
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.
Cross Domain REST with Backbone.js and .NET MVC 3
I’m working on a small project within a bigger web application where an all-javascript solution made the most sense. In the past I’ve used Knockout.JS and had a lot of fun with it. It was simple to learn and easily added some robust javascript functionality on top of a .NET MVC project that would have been much more difficult in straight jQuery.
For this project, however, Backbone.js made more sense because we wanted all the logic to be built without having to add any server-side code. All data access would be done though a separate set of web services.
The problem is:
- Backbone.js wants to implement a REST interface to backend web services
- The web services I would be accessing would not be on the same domain as the javascript.
- And some combination of IIS and Windows are not friendly to REST. Specifically PUT and DELETE requests can easily get blocked.
I ended up giving up on trying to implement REST with the correct HTTP PUT AND DELETE methods. Several searches and attempts pointed possibly to WebDAV interfering. I also found other sites (like the IIS Express FAQ) that said PUT and DELETE just needed to be allowed in the applicationHost.config file. Nothing worked. But more importantly, even if I had it working in a local dev environment within Visual Studio, it didn’t look like things would be easy to deploy. Instead I took advantage of the fact that MVC 3 and Backbone.js support X-HTTP-Method-Override. Just set Backbone.emulateHTTP = true; and you can use REST-like attributes like [HttpPut] on your controller actions.
Now for the cross domain part….
When making a cross domain connection, jQuery will do the following:
- Send a preflight request with an OPTIONS method. This request will verify whether the server will allow the real request. The response from the server must include:
- A list of valid HTTP methods (Access-Control-Allow-Methods)
- A list of valid HTTP headers (Access-Control-Allow-Headers)
- The requesting domain in the Access-Control-Allow-Origin header.
- If the OPTIONS request was successful, it will send the real request. This request must also respond with a valid Access-Control-Allow-Origin header.
Here is and ActionFilterAttribute I use to accomplish that:
https://gist.github.com/1854201
The problem, however, is that even with that in place, you won’t necessarily have anything setup to respond to a request with an HTTP OPTIONS method. In my case, I setup a route and controller action to specifically handle that. It doesn’t do anything other than return the correct headers from the ActionFilterAttribute. There’s probably a better way to handle this, but it’s working nicely for me right now.
And finally, change the jQuery setting to turn CORS on:
$.support.cors = true;
CoffeeScript in Sublime Text on Windows
I work on both Ubuntu and Windows, and just recently switched to the Sublime Text 2 editor, which is a nice cross between TextMate and vim, and runs cross platform. Everything runs as expected on Ubuntu, not so much on Windows. Here’s what you need to do to get CoffeeScript highlighting and building:
- Install Node using the new Windows installer. This also installs npm.
- Open a cmd window
- Install CoffeeScript as you would normally: npm install -g coffee-script
- Reboot - all should be loaded into your PATH variable correctly
- For highlighting, git clone jashkenas’ coffee-script-tmbundle from GitHub into C:\Users<User>\AppData\Roaming\Sublime Text 2\Packages\CoffeeScript
- At this point the building doesn’t work. Open up the build file: C:\Users<User>\AppData\Roaming\Sublime Text 2\Packages\CoffeeScript\Commands\CoffeeScript.sublime-build and have it look like the following:
{
"shell" : true,
"cmd": ["coffee","-c","$file"],
"file_regex": "^(...*?):([0-9]*):?([0-9]*)",
"selector": "source.coffee"
}
Essentially you need to remove the “path” variable that’s there and add in the “shell” variable set to true so it runs from cmd.exe.
Knockout.js
I just finished my first non-trivial web app that leverages Knockout, a framework that helps you build better javascript front-end applications. While Knockout isn’t nearly as popular as Backbone.js is, I think it serves a different purpose, even though they’re typically lumped together. There’s a great set of answers on Backbone vs Knockout on StackOverflow about this, but the fact that a post like that exists proves the point.
For me, I picked it because:
- I only wanted to add functionality to a single page of my application, rather than build an entire single-page app.
- The data-bind attributes are a little ugly, but expressive at least. So I think it’s easy to read the HTML and understand what’s going on without even really looking at the javascript.
- Accomplishing most things in Knockout requires less code than Backbone.
I wanted to improve the performance of a search page. Essentially the functionality allows users to search for products from a number of vendors based on the location of that vendor. So, for example, “Show me all instructors offering tennis lessons in the Boston area.” The results page would then be broken down by instructor, and a list of their offerings in that category.
Here’s what I implemented in Knockout:
- Search results load on demand via jQuery json calls to the server.
- I aggressively cache data using local storage. In this case I used store.js from Marcus Westin to simplify browser compatibility.
- With the caching, I intercept updates to the UI by hooking into the Knockout subscribe and only loading data via ajax that isn’t already in the cache.
- Local storage also saves the current state of the page if you’ve already saved items in your cart. We don’t have a need to save cart information on the server, so local storage made sense. If you clear your cart, it will also clear the cache next time you visit the page to make sure you get the most updated data.
- Data is submitted via a hidden form field, similar to what Steven Sanderson lays out in his post.
- All written in CoffeeScript, of course.
Two things worth pointing out that helped me:
- First, Ryan Niemeyer’s blog Knock Me Out has a great set of posts on Knockout. Start with 10 things to know about KnockoutJS on day one, but explore from there.
- Second, surprisingly enough was reading the Knockout source code on Github. I think javascript is incredibly hard to follow because of it’s prototype nature, but this helped me figure out some additional things that just aren’t covered in the Knockout documentation.
In Support of Code Reviews
Ok, its tough not to laugh at this post from Ayende. He’s going through the process of trying to hire someone for his team, and asks those who apply to complete some simple programming tasks. I’m sure he’s glad he does.
But how did this happen? How did someone write code this bad?
Let’s make some assumptions. I think Ayende wouldn’t have wasted this person’s time as well as his own if the person didn’t pass at least an initial resume review. That means they probably have a base level set of experience:
- The developer probably has some degree in a computer-related field. Maybe a B.S. in Computer Science. Maybe even a higher degree.
- I don’t believe he’s hiring at the entry level, so this developer has probably worked at least a couple years as programmer in a paying position.
- Applying for a .NET/C# job here means this person feels most comfortable in that language.
This should give them every opportunity to become a valuable contributor as a programmer.
From looking at the code, however, we can tell they really only know:
- In ASP.NET Webforms you can bind an event to a button click.
- How to pass a hard coded sql query to a database connection and get query results back.
- That wrapping your code in a try/catch block keeps your code from crashing with an ugly error message - especially if you don’t bother writing the “catch” part.
In other words, just enough to squeeze by if no one ever looks at your code.
Compile this application and put it up for your (non-technical) manager or client to review and everything works fine. No one tells you it’s bad, so the next time you have to build something similar, you do the same thing again. It’s all you know. Without code reviews, I imagine a developer could go years thinking they’re building up their resume, only to be disappointed the first time someone actually does dive deep into their work.
Now, this might be a blatant example, but there are more subtle ones everyday. If you’re a programmer, do yourself a favor find a coding buddy if you haven’t already.
(617) 863-7429