A while ago I started using HEAD requests via Ajax in some apps and thought I'd write a few notes about why. Basically it's to improve user interfaces/experience when things start getting complicated.

Just in case anyone didn't know, HEAD is one of the standard HTTP request types. Everyone knows GET and POST, and if you've done RESTy stuff you should know the others too. Here's the W3C docs for the full set.

The key part about HEAD requests is that the request and response contain no body - it's just headers going both ways. So it's pretty speedy and there shouldn't be any heavy processing going on in the server to handle it. This makes it handy for quick status messaging (are you there? does this page exist? did I already ask for this? how busy are you?)

HEAD occasionally gets forgotten, so it sometimes isn't supported in hand-rolled services/frameworks. That shouldn't be a reason to avoid using HEAD - if a bit of framework doesn't work, it needs fixing. If in doubt, allow HEAD requests through to your serious code just as if they were GET requests. So, lets assume HEAD requests are filtered/routed properly for the rest of this article.

(no sniggering at the back)

It turns out mobile browsers often use HEAD requests before doing GET/POST requests for large resources, to check whether they already have the content and if it has changed since last time they requested it.

This means that we can help optimise mobile behaviour by handling HEAD requests for larger and more processing intensive requests. If a HEAD request fails, the browsers make the following GET/POST request anyway, so there's a recognisable pattern in your web access logs for this kind of behaviour.

I've mainly been using HEAD requests via jQuery Ajax requests as part of Javascript user interfaces in web apps that integrate with other services or provide access to some complex server-side processing. This is for things like checking if a service/app is available and getting status info about a long running process. Depending on the response a bit of Javascript will might toggle a chunk of the page to avoid the user seeing links to stuff they can't use, or inform them of some server status/activity.

More generally this means we can do things like:

  • Hide links to an app while it is active but unavailable for use (maybe for routine maintenance, or feeling overloaded)
  • Hide links that aren't appropriate for the user (Note - not for security reasons, but for usability - remember rule 1 of client-server apps: "never trust the client")
  • Show a link to a result when some long running async processing has completed (e.g. we have generated your pack of documentation)
  • Set up a dashboard page showing the status of various apps (yes, there are better ways to do this)
  • For a GET/POST request needing some heavy processing, a HEAD request for the same thing could return a 304 (Not Modified) to indicate the browser already has the latest version of the response - can avoid the user triggering repeated requests for the same large chunk of work.
  • For a GET/POST request which we know will have a big response, we could support a HEAD request for the same thing that returns a 200 with a content length set to whatever the GET/POST response would be (or a rough approximation anyway). That lets the Javascript side show a proper progress bar rather than an animation, or otherwise let the user know what's coming.

In an online survey app I worked on, I added a controller method to support HEAD requests to determine if a survey is active (this is simplified, the real code is a bit cleverer):

Spring3 Controller method

@RequestMapping(value = "/{surveyId}", method = RequestMethod.HEAD)
public ResponseEntity<String> surveyExists(@PathVariable(value = "surveyId") String surveyId) {
    if (surveyService.active(surveyId)) return new ResponseEntity<String>(HttpStatus.OK);
    return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}

In the target app page there was an initially hidden link to the survey, ready to be shown if its survey is active. That way if the survey isn't active, or the survey app is dead, the link stays hidden and the user doesn't see a link that'll give them a 404 if they hit it.

That page has a chunk of Javascript to check if the survey is active by making a HEAD request to the controller method above, and un-hiding the link if we get an HTTP OK in the response.

Javascript/jQuery

// do a HEAD request for the survey. If we get a sane
// response turn on the survey link, otherwise don't.
$.ajax({
    url: "/survey/myApp",
    type: 'HEAD',
    success: function(data){
        // survey is active
        $("#survey-iframe").attr("src", "/survey/myApp");
        $("#survey-section").show();
    },
    error: function(xhr, msg, status) {
        // any error means we shouldn't show the link
    }
});

Looking at the Java, HEAD methods don't return any bodies (no JSP, XML, JSON, etc) so we just set up a ResponseEntity and give it the relevant HttpStatus - which sets the relevant response code (OK = 200, NOT_FOUND = 404, etc).

In the Javascript (jQuery), 4xx and 5xx responses trigger the ajax.error function - as does getting no response at all from the request (e.g. because the server isn't active).

The ajax.error function gets 3 params, or 2 if you're on an old version of jQuery. If you're on an old jQuery, the status text is held in the xhr.statusText field. If you're on a newer jQuery the 3rd status param contains the same string.

For the survey app I worked on, I used a 410 (HttpStatus.GONE) to indicate an active survey which the user has already responded to. That changed my Ajax code to look something like this:

$.ajax({
    url: "/survey/myApp",
    type: 'HEAD',
    success: function(data){
        // survey is active and the user hasn't seen it yet
    },
    error: function(xhr, msg, status) {
        if (xhr.statusText == "Gone" || status == "Gone") {
            // survey is active but user has already responded
            // supports jquery 1.4.x and 1.11.x status params
        }
        // survey isn't active for some reason, don't show the link
    }
});

We can actually set any HTTP header details we like on the server, and handle them any way we like in the Javascript. So we could abuse the way the responses are used - treat a 200 as a failure case, set the content-length to arbitrary values, etc. But that's not a nice way to behave, so don't do that. Try to follow the intent of the HTTP methods in that RFC I linked at the top.

Arguably my using GONE status to indicate "user has already done this" is a bit of an abuse. I wouldn't argue with that, but I think it passes the cardinal rule of potentially awkward code - will it be obvious to another developer who has to deal with this code when you're not around?

Use HEAD if you want to know if an app or server is up (and happy) before pointing the user at it.

Use HEAD if you don't need any content response, just a simple status.

Think about providing HEAD request variants for large processing requests, to give some prior info/warning.

Try to follow the intent of the status responses not just pick randomly from the 4xx, 5xx. Don't use 418 (I'm a teapot)

Don't forget about HEAD requests if you're writing filter / interceptor / router rules and logic

Previous Post Next Post

© Me. Best viewed with a sense of humour and a beer in hand.