Concepts

Conditional requests allow browsers and servers to agree to “skip” a full response under certain conditions. This can be done in two different ways: the Last-Modified header and the ETag header. They are described in full in the very readable RFC 7232 Conditional Requests. What follows is a brief overview of the two different forms.

Last-Modified

The “Last-Modified” header field in a response provides a timestamp indicating the date and time at which the origin server believes the selected representation was last modified, as determined at the conclusion of handling the request.

RFC 7232 Section 2.2 Last-Modified

The Last-Modified header is simply a timestamp of the last time the content of a particular url was modified. It is up to the server to set decide which timestamp to provide. In the case of Django Conditional Views, ConditionalGetTemplateViewMixin uses the last modified time of the template, ConditionalGetDetailViewMixin uses a configurable last_modified field on the object, and ConditionalGetListViewMixin uses the latest value of a configurable last_modified field on the queryset.

When a browser requests a url whose response includes the Last-Modified header, they may supply the If-Modified-Since header on subsequent requests to that url. For example if the first request to a url returned a Last-Modified Tue, 28 Aug 2018 22:31:21 GMT header, then subsequent requests to that url would provide a If-Modified-Since Tue, 28 Aug 2018 22:31:21 GMT, instructing the server to only provide the normal response if the content would have a Last-Modified timestamp newer than that. If the server decided that the content was not newer, it would return a 304 (Not Modified) response instead, and the browser would load the previous response from its cache and show that to the user instead.

ETag

An entity-tag is an opaque validator for differentiating between multiple representations of the same resource, regardless of whether those multiple representations are due to resource state changes over time, content negotiation resulting in multiple representations being valid at the same time, or both. An entity-tag consists of an opaque quoted string, possibly prefixed by a weakness indicator.

An entity-tag can be more reliable for validation than a modification date in situations where it is inconvenient to store modification dates, where the one-second resolution of HTTP date values is not sufficient, or where modification dates are not consistently maintained.

RFC 7232 Section 2.3 Etag

The Etag – short for “entity tag” – header has as its value a string provided by the server that uniquely identifies the response. For example, in the Django Conditional Views ConditionalDetailViewMixin the default ETag is generated by hashing the response.content, ie the rendered html of the page. As any change to the page would change the hash, the hash is able to serve as a unique identifier of that particular page.

When a browser requests a url whose response includes an Etag, for example Etag "da341451e4ad4c969dc88e2924208508", the browser may append a new header to all subsequent requests: If-None-Match "da341451e4ad4c969dc88e2924208508". This instructs the server to return the normal response for this url unless the response would have that specific ETag.

If the server decides that the response would indeed have that Etag, for example because it is using the response content hashing mechanism described before, then the server would respond 304 (Not Modified), and the browser would load the previous response from its cache and show that to the user instead.