Essential HTTP Headers

Posted by Anandhan Subbiah on May 12, 2009 in Programming Concepts, Technical ArticlesNo comments

Age
Type: Response header

If the response entity-body does not come fresh from the server, the Age header is a measure of how long ago it left the server. This header is usually set by HTTP caches, so that the client knows it might be getting an old copy of a representation.

Cache-Control
Type: Request and response header

This header contains a directive to any caches between the client and the server (including any caches on the client or server themselves). It spells out the rules for how the data should be cached and when it should be dumped.

Content-Type
Type: Response header

Definitely the most famous response header. This header tells the client what kind of thing the entity-body is. On the human web, a web browser uses this to decide if it can display the entity-body inline, and which external program it must run if not. On the programmable web, a web service client usually uses this to decide which parser to apply to the entity-body.

Date
Type: Request and response header.

As a request header, this represents the time on the client at the time the request was sent. As a response header, it represents the time on the server at the time the request was fulfilled. As a response header, Date is used by caches.

ETag
Type: Response header.

The value of ETag is an opaque string designating a specific version of a representation. Whenever the representation changes, the ETag should also change.

Whenever possible, this header ought to be sent in response to GET requests. Clients can use the value of ETag in future conditional GET requests, as the value of If-None-Match. If the representation hasn’t changed, the ETag hasn’t changed either, and the server can save time and bandwidth by not sending the representation again.

The main driver of conditional GET requests is the simpler Last-Modified response header, and its request counterpart If-Modified-Since. The main purpose of ETag is to provide a second line of defense. If a representation changes twice in one second, it will take on only one value for Last-Modified-Since, but two different values for ETag.

Expires
Type: Response header

This header tells the client, or a proxy between the server and client, that it may cache the response (not just the entity-body!) until a certain time. Even a conditional HTTP GET makes an HTTP connection and takes time and resources. By paying attention to Expires, a client can avoid the need to make any HTTP requests at all—at least for a while.

The client should take the value of Expires should as a rough guide, not as a promise that the entity-body won’t change until that time.

If-Modified-Since
Type: Request header

This request header is the backbone of conditional HTTP GET. Its value is a previous value of the Last-Modified response header, obtained from a previous request to this URI. If the resource has changed since that last request, its new Last-Modified date is more recent than the one. That means that the condition If-Modified-Since is met, and the server sends the new entity-body. If the resource has not changed, the Last-Modified date is the same as it was, and the condition If-Modified-Since fails. The server sends a response code of 304 (”Not Modified”) and no entity-body. That is, conditional HTTP GET succeeds if this condition fails.

Since Last-Modified is only accurate to within one second, conditional HTTP GET can occasionally give the wrong result if it relies only on If-Modified-Since. This is the main reason why we also use ETag and If-None-Match.

If-None-Match
Type: Request header

This header is also used in conditional HTTP GET. Its value is a previous value of the ETag response header, obtained from a previous request to this URI. If the ETag has changed since that last request, the condition If-None-Match succeeds and the server sends the new entity-body. If the ETag is the same as before, the condition fails, and the server sends a response code of 304 (”Not Modified”) with no entity-body.

If-Unmodified-Since
Type: Request header

Normally a client uses the value of the response header Last-Modified as the value of the request header If-Modified-Since to perform a conditional GET request. This header also takes the value of Last-Modified, but it’s usually used for making HTTP actions other than GET into conditional actions.

Let’s say you and many other people are interested in modifying a particular resource. You fetch a representation, modify it, and send it back with a PUT request. But someone else has modified it in the meantime, and you either get a response code of 409 (”Conflict”), or you put the resource into a state you didn’t intend.

If you make your PUT request conditional on If-Not-Modified, then if someone else has changed the resource your request will always get a response code of 417 (”Precondition Failed”). You can refetch the representation and decide what to do with the new version that someone else modified.

This header can be used with GET, too; see the Range header for an example.

Last-Modified
Type: Response header

This header makes conditional HTTP GET possible. It tells the client the last time the representation changed. The client can keep track of this date and use it in the If-Modified-Since header of a future request.

In web applications, Last-Modified is usually the current time, which makes conditional HTTP GET useless. Web services should try to do a little better, since web service clients often besiege their servers with requests for the same URIs over and over again.

User-Agent
Type: Request header

This header lets the server know what kind of software is making the HTTP request. On the human web this is a string that identifies the brand of web browser. On the programmable web it usually identifies the HTTP library or client library that was used to write the client. It may identify a specific client program instead.

Soon after the human web became popular, servers started sniffing User-Agent to determine what kind of browser was on the other end. They then sent different representations based on the value of User-Agent. Elsewhere in this book I’ve voiced my opinion that it’s not a great idea to have request headers like Accept-Language be the only way a client can distinguish between different representations of the same resource. Sending different representations based on the value of User-Agent is an even worse idea. Not only has User-Agent sniffing perpetuated incompatibilities between web browsers, it’s led to an arms race inside the User-Agent header itself.

Almost every browser these days pretends to be Mozilla, because that was the internal code-name of the first web browser to become popular (Netscape Navigator). A browser that doesn’t pretend to be Mozilla may not get the representation it needs. Some pretend to be both Mozilla and MSIE, so they can trigger code for the current most popular web browser (Internet Explorer). A few browsers even allow the user to select the User-Agent for every request, to trick servers into sending the right representations.

Don’t let this happen to the programmable web. A web service should only use User-Agent to gather statistics and to deny access to poorly-programmed clients. It should not use User-Agent to tailor its representations to specific clients.

Cookie
Type: Request header

This is probably the second-most-famous HTTP header, after Content-Type, but it’s not in the HTTP standard; it’s a Netscape extension.

A cookie is an agreement between the client and the server where the server gets to store some semipersistent state on the client side using the Set-Cookie header (see below). Once the client gets a cookie, it’s expected to return it with every subsequent HTTP request to that server, by setting the Cookie header once for each of its cookies. Since the data is sent invisibly in the HTTP headers with every request, it looks like the client and server are sharing state.

Cookies have a bad reputation in REST circles for two reasons. First, the “state” they contain is often just a session ID: a short alphanumeric key that ties into a much larger data structure on the server. This destroys the principle of statelessness. More subtly, once a client accepts a cookie it’s supposed to submit it with all subsequent requests for a certain time. The server is telling the client that it can no longer make the requests it made precookie. This also violates the principle of statelessness.

If you must use cookies, make sure you store all the state on the client side. Otherwise you’ll lose a lot of the scalability benefits of REST.

Reference : RESTful Web Services
by Leonard Richardson; Sam Ruby

  • Share/Bookmark
Tags: ,

Leave a comment