A question that I see come up often is why Angular’s $http AJAX methods seem to be incompatible with server-side features in popular frameworks like ASP.NET MVC, Express, Django, and Rails that modify their responses for AJAX-based requests.

Examples range from partial rendering techniques like Rails’ Turbolinks (aka UpdatePanel 2.0) to endpoints that respond with nothing but a JSON representation of the page’s content instead of rendering HTML at all. A wide range of these sort of server-side features in various frameworks and libraries work that way, so the discrepancy between the behavior in Angular vs. client-side libraries like jQuery can be puzzling.

In this post, I’ll briefly explain the mechanism that your server-side framework uses to detect AJAX requests, show you how to make a single Angular $http request compatible with that mechanism, expand that to automatically apply to all requests sent through any $http method, and then explain why Angular doesn’t seem to work right by default.

How does the server know, and why?

About a decade ago, while Web 2.0’s founding JavaScript libraries were still in their infancy, a de facto standard arose to identify AJAX requests originating from those libraries. Still prevalent today, that standard is an X-Requested-With HTTP header carrying the value XMLHttpRequest.

Originally, the header was added for security reasons. Testing for its presence is one way to provide rudimentary protection against cross-site request forgery (CSRF) attacks in certain situations. Using anti-forgery tokens is a much better solution for CSRF protection, but the X-Requested-With header found even more uptake as a convenient way to make a single URL to respond with different content for AJAX requests (e.g. Turbolinks and pjax).

At present, you’ll still see that header sent along with every jQuery $.ajax() request. For example, running this simple code:

Then inspecting the request headers that were sent verifies that the X-Requested-With header is present:

An example of the headers sent via a jQuery $.get('/controller/action')

Over time, the reliable presence of this header led many server-side frameworks to include built-in “IsAJAX?” convenience methods to test for it. E.g., Request.IsAjaxRequest() in ASP.NET MVC, request.xhr? in Rails, and req.xhr in Express.

Surely Angular supports this standard too, right?

Simple as it is, it might seem like adding the X-Requested-With header is an obvious thing for Angular’s $http methods to do. Unfortunately, Angular does not.

For example, this is how you might translate the jQuery code in the previous section to Angular’s $http:

If you run that and then take a look at the request’s headers in your browser’s dev tools:


Angular doesn’t send the X-Requested-With header by default.

You can see that the X-Requested-With header really is missing from the request. Angular actually added the header by default in the past, but dropped it a couple years ago.

Adding the X-Requested-With header to Angular’s requests

It’s easy to instruct Angular to add custom HTTP headers to requests through $http. Knowing what we now know about the missing X-Requested-With header, this is how we can add that header to an individual request:

If you run that code and inspect its request headers, you’ll see that the correct header is now included:

That’s more like it!

Getting it working for a single request is fine. However, it would be a lot nicer to never have to remember to manually add the header, as if you were using something like jQuery’s $.ajax().

Adding the header to every request automatically

As it turns out, configuring Angular to add the X-Requested-With header back to every $http request is nearly as easy as adding it to a single request. You can do that by adding the header to $httpProvider‘s defaults in an Angular configuration block:

Now, every request your code makes through $http will include the X-Requested-With header.