Accessing the Location header in a CORS-enabled API

Thursday, Nov 28, 2013 2 minute read Tags: asp-net ajax cors
Hey, thanks for the interest in this post, but just letting you know that it is over 3 years old, so the content in here may not be accurate.

Today I hit a problem, we’ve got an ASP.Net WebAPI 2 project which is providing a series of REST services for a web app. These services are hosted on a different domain to the app will be hosted on so to perform the requests to them we’ve gone ahead and enabled CORS.

Up until now most of our work has been doing read-only endpoints in the API, but I just finished off implementing a POST route. Now in a RESTful API a POST should return a 201 Created response along with the location which which you’ll find the newly created resource. So in WebAPI I have something like this:

var response = Request.CreateResponse(HttpStatusCode.OK, createdItemId);
response.Headers.Location = new Uri(Url.Link("SomeRoutes", new { id = createdItem }));

Which sees me having a Location header in my response.

Next I want to read out the Location header and then follow it to get the data and display it on screen. I’m using AngularJS for this but the principle is the same for any way you’re performing an AJAX request:

$http.post(someUrl, someData)
    .then(function (response) {
        var location = response.headers('Location');

        return $http.get(location);
    })
    .then(function (response) {
        console.dir(response.data);
    });

Only there’s a problem, location is always undefined! I’m looking in my network tab in the dev tools and I can clearly see that there is a Location header returned but when I try and read it in JavaScript it’s never there.

Frustrated I turned to the googles and was not having much luck, everyone just said response.headers('Location') and you’ll have your header, but I was never seeing it from Angular, or even in the raw xhr object. Something must be wrong.

After some more digging I came across this. Little did I know that if you’re enabling CORS it will only expose a small number of the available headers by default, if you want more you have to expose them.

So back to our WebAPI controller action I added the following:

var corsResult = new CorsResult();
corsResult.AllowedExposedHeaders.Add("Location");
response.WriteCorsHeaders(corsResult);

My API is already CORS enabled, all I’m doing is telling it that it’s a CORS response and I want some additional headers exposed cross-origin.

And now I’m able to read my Location header in JavaScript.