Access-Control-Allow-Origin in preflight response doesn't enable cross-domain access

I am trying to send a CORS request using AJAX to a nodeJS server. I want to return some JSON data. I've found numerous tutorials online that all say the same thing, which I've tried, but I can't get this to work. Here's the AJAX request:

$.ajax({
        url: "http://some.other.url.com:8880",
        type: "GET",
        crossDomain: true,
        contentType: 'application/json'
    }).then(function(response) {
        $scope.allData = jQuery.parseJSON( response );
        console.log($scope.allData);
    }).fail(function(response) {
});

And here is the code on the server:

var path = url.parse(req.url).pathname,
    match = router.match(path),
    rescode;

    console.log("---: " + req.method);

if (req.method === 'OPTIONS') {
    var headers = {};
    headers["Access-Control-Allow-Origin"] = "*";
    headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, OPTIONS";
    headers["Access-Control-Allow-Credentials"] = false;
    headers["Access-Control-Max-Age"] = '86400'; // 24 hours
    headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept";
    res.writeHead(200, headers);
    return res.end();
}

I'v also tried it without the return on res.end() i.e. not returning the OPTIONS preflight request, and that doesn't work either.

--Edit-- Here is the actual error message in the console:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://other.domain.com:8880/. This can be fixed by moving the resource to the same domain or enabling CORS.

The server is getting the requests. Both the OPTIONS and then GET requests are hitting the server and being responded to. In fact, in the console log for the page making the AJAX request, I can click on the CORS error and see the response, and it is the correct data. But I can't seem to get the javascript to continue.

In regards to .done vs .then, they seem to work interchangeable. Or at least, in this example, the .then and .fail are working just fine.

You're correctly setting CORS headers in your OPTIONS preflight response, but you also need to set Access-Control-Allow-Origin (either to your origin or *) on your actual GET response. The GET response should respond with the same CORS headers, regardless of whether there was a preflight response or not. This means that it must send the appropriate CORS headers, but it does not need to send anything except for Access-Control-Allow-Origin. (If other non-simple components like non-simple verbs or headers are involved, they will be allowed or denied in the preflight; the actual GET response does not need to worry about them.)

The Enable CORS site has a CORS testing tool to help you see the headers involved in a request that you specify. I've used that tool to set up a test similar to your case (GET with non-simple Content-Type header). If we examine the results of that test (careful -- the steps are presented little bit out of order, but they're all there), we see a preflight response:

Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS
...
Access-Control-Allow-Origin: http://client.cors-api.appspot.com
Access-Control-Allow-Headers: X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept

And the final CORS response:

Content-Length: 0
Content-Type: application/json
Access-Control-Allow-Origin: http://client.cors-api.appspot.com
Cache-Control: no-cache

As you can see, the GET response also has a Access-Control-Allow-Origin header and no other CORS headers. If you have any further uncertainties, feel free to tweak the settings on that tool to run a wide range of other test cases.