sajad torkamani


The Cache-control header can have one of three values:

  • public: public proxy servers can cache the response. Suitable for resources that can be shared between multiple users (e.g., home page logo or website icons).
  • private: only the browser can cache the response. Suitable for user-specific content (e.g., HTML page showing user’s images).
  • no-store: nobody should cache the response because it contains sensitive information that shouldn’t be persisted in memory.

A server can also specify a max-age value in the Cache-control header. This tells clients the number of seconds to cache the response.

HTTP/1.1 200 OK
Last-Modified: Wed, 25 Jan 2012 17:55:15 GMT
Expires: Sat, 22 Jan 2022 17:55:15 GMT
Cache-Control: max-age=315360000,public


Cache-Control: max-age=604800

Specifies that the response is fresh until X seconds after the response was generated so caches can store and reuse this response for subsequent requests whilst it’s fresh.


If-Modified-Since can be used by clients to check if a cache is still valid.

GET http://… HTTP/1.1
If-Modified-Since: Wed, 25 Jan 2012 17:55:15 GMT

This tells a server that the client only needs the full response if the cache is stale. If the cache is still valid, the server responds with:

HTTP/1.1 304 Not Modified
Expires: Sat, 22 Jan 2022 17:16:19 GMT
Cache-Control: max-age=315360000,public

This tells the client it can still use its cache.


The ETag is usually computed (using a hash function) from the resource’s contents or a version number determined from the file name. If the resource changes, the server generates a new ETag. Clients can check if the ETag of a response matches an existing cache entry. If so, the cache is still valid, otherwise, it’s time to invalidate it.

For example, a response for an index.html file might return the following:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
ETag: "33a64df5"
Cache-Control: max-age=3600

<!doctype html>

If the response is stale, the client will take the value of the ETag response header for the cache response, and set it in the If-None-Match request header to ask the server if the cached resource has been modified:

GET /index.html HTTP/1.1
Accept: text/html
If-None-Match: "33a64df5"

The server will check the latest ETag of index.html (using whatever hashing / version number mechanism it uses) and return a 304 Not Modified response if it’s still the same. If it’s different, it will return a new ETag response header and with a 200 OK response with the latest version of the resource.

HTTP/1.1 200 OK 
Server: Apache 
Last-Modified: Fri, 06 Jan 2012 18:08:20 GMT 
ETag: "8e5bcd-59f-4b5dfef104d00" 
Content-Type: text/xml 
Vary: Accept-Encoding 
Content-Encoding: gzip 
Content-Length: 437


Indicates what parts of the request message influence the response content besides the method and URL. In practice, Vary is used to create a cache key when content negotiation is in use. For example, if your web application supports multiple languages, you may specify:

Vary: Accept-Language

So that requests that contain the Accept-Language: en-US have a separate cache entry to those with Accept-Language: ja-JP. You wouldn’t want US visitors to receive the same response as Japanese visitors.

Vary HTTP caching header

Another potential value is Accept-Encoding for when you don’t cached gzip responses to be served to a client that doesn’t support gzipped-encoded responses.

Sources / related