According to the W3C we have the following definitions for http response codes: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
200 Status code according to the W3C
10.2.1 200 OK
The request has succeeded. The information returned with the response is dependent on the method used in the request, for example:
GET an entity corresponding to the requested resource is sent in the response;
HEAD the entity-header fields corresponding to the requested resource are sent in the response without any message-body;
POST an entity describing or containing the result of the action;
TRACE an entity containing the request message as received by the end server.
304 Status code according to the W3C
10.3.5 304 Not Modified
If the client has performed a conditional GET request and access is allowed, but the document has not been modified, the server SHOULD respond with this status code. The 304 response MUST NOT contain a message-body, and thus is always terminated by the first empty line after the header fields.
The response MUST include the following header fields:
- Date, unless its omission is required by section 14.18.1
If a clockless origin server obeys these rules, and proxies and clients add their own Date to any response received without one (as already specified by [RFC 2068], section 14.19), caches will operate correctly.
- ETag and/or Content-Location, if the header would have been sent in a 200 response to the same request
- Expires, Cache-Control, and/or Vary, if the field-value might differ from that sent in any previous response for the same variant
If the conditional GET used a strong cache validator (see section 13.3.3), the response SHOULD NOT include other entity-headers. Otherwise (i.e., the conditional GET used a weak validator), the response MUST NOT include other entity-headers; this prevents inconsistencies between cached entity-bodies and updated headers.
If a 304 response indicates an entity not currently cached, then the cache MUST disregard the response and repeat the request without the conditional.
If a cache uses a received 304 response to update a cache entry, the cache MUST update the entry to reflect any new field values given in the response.
200 (from cache) vs 304
Now the other day while performing a site performance audit I noticed that a lot of our assets were returning 304 statuses. While comparing another site I noticed that it was returning a 200 (from cache) status code. This intrigued me and I wanted to dig deeper.
It turns out that when a 200 (from cache) response is given it means that a future expiration date on the content is set. In essence the browser doesn’t even really communicate with the server to check on the file. It knows not to do it until the expiration date has expired.
By contrast a 304 goes to the server and receives a response back that the data has not change. The server is telling the browser to use the cache as a result.
So which do you use?
Now here is the tricky question. Which do you use?
If your assets do not change a lot – then use the cache expiration settings and get the most out of your browser cache. you will see 200 (from cache) being used by your browser and you can enjoy the bliss of fast loading assets. The time you choose really depends on how frequently your site changes. Weekly, Monthly, Yearly, etc…
Let’s now assume that you have a site that changes very frequently. Maybe you hotfix out JS patches on a daily basis. Using a far-reaching expiration date would actually cause problems as you would patch your JS – but browsers will not check for updates until the cache expires. If you only have a small number of links then there is a quick hack approach you could take which is pretty simple to maintain. A quick and dirty way around this is the set a simply query string on the end of your asset. Something like “file.js?v=1”. When you change file.js you simply change the link to the file to be “file.js?v=2”.
If you have a large number of links the solution above can easily fall apart and be difficult to maintain. Here is where good engineering comes in. I have worked with engineers who created a unique version url per asset. In order to get a URL for an asset you had to go through a common function. This function maintained a relation between an asset and a commit version number (such as the SVN or GIT commit revision number). After you requested your asset you would get a string that looked something like this: http://site.com/asset.jpg?v=####. During a new build it would pick up and update all of the new version numbers and append them to the asset urls. When time allows I may deep dive into this solution more – but hopefully for now the quick and dirty explanation will suffice.