10

I'm trying to have a basic behavior regarding my caching strategy: files should be cached, and revalidated with server each time. So I would like Apache to send a 304 back.

Here is the dialog that happens for each browser refresh:

Status Code:200 OK

Request Headers

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Cookie: ...
Host:...
If-Modified-Since:Tue, 14 Oct 2014 15:10:37 GMT
If-None-Match:"1461-505636af08fcd-gzip"
User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36

Response Headers

Accept-Ranges:bytes
Cache-Control:No-cache
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:1412
Content-Type:text/html
Date:Tue, 14 Oct 2014 16:58:05 GMT
ETag:"1461-505636af08fcd-gzip"
Keep-Alive:timeout=5, max=99
Last-Modified:Tue, 14 Oct 2014 15:10:37 GMT
Server:Apache/2.4.6 (Ubuntu)
Vary:Accept-Encoding

(this is from chrome devtools, with Disable cache unchecked)

You can see that the response contains the Cache-Control:No-cache Header, and that the If-modified-since header matches the Last-modified. The ETag matches too.

Shouldn't Apache sends a 304 in that case ?

EDIT

Disabling ETags in apache with

 Header  unset ETag

makes the caching behavior more predictible...

zrz
  • 243
  • 1
  • 5
  • 10
  • I think `Cache-Control:max-age=0` disabled the cache, so you see the `Cache-Control:No-cache` response. – ThoriumBR Oct 14 '14 at 17:24
  • I explicitly set Cache-Control:No-cache in my apache config because from http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1, I understand that it causes revalidation for each request. Does revalidation implies re-sending the file ? I would say it should use If-modified-since to determine if it's a 200 or a 304. – zrz Oct 14 '14 at 17:37

3 Answers3

8

This seems to be an old bug, explaining why Header unset ETag makes a difference.

Apache 2.4.0+ automatically appends the compression method name to the ETag (as seen in your headers), and prevents a 304 response.

Newest versions of mod_deflate support a DeflateAlterETag that can be used to control this behavior:

DeflateAlterETag NoChange
Mathias R. Jessen
  • 24,907
  • 4
  • 62
  • 95
  • 3
    This is correct but Apache 2.4 doesn't contain that option, only Apache 2.5. However personally I don't find ETags that useful since Apache bases them off the last modified date, rather than the file contents. So turning off ETags falls back to If-Modified-Since header, which is based on last modified date anyway. You can alter the ETag in Apache to make it based off of size, last-modified and/or inode - with size and last modified being the default - but, until they add an option to calculate an ETag based on checksum of file contents, its of limited use IMHO. So I turn them off. – Barry Pollard Jun 08 '15 at 22:04
  • 1
    @BazzaDP That makes sense. 2.5 also has a `DeflateAlterETag Remove` option to does just that – Mathias R. Jessen Jun 09 '15 at 10:17
  • So the most popular webserver on the planet does not properly support client-side caching with compression, and this bug has been at large for more than 10 years. Unbelievable. – Sam Watkins Jun 25 '20 at 12:28
0

This one stands out in the request as being a bit odd:

Cache-Control:max-age=0

Likely more important though, I notice that the returned content is html. Is it being dynamically generated? Apache MAY send a 304 response, but unless you're serving static content, it's not Apache's job to make that call, and it comes down to your application logic. E.g. most php applications have limited support for such things.

A front end cache may help, as the caching app can check the modification time, etag, etc., but only if both the application and the request headers are cache friendly. Eg the application has to set appropriate headers to indicate the content is cacheable, and things like the Cache-control header in your request will negate the cache. Your headers are not looking cache friendly.

mc0e
  • 5,786
  • 17
  • 31
  • The requested file is a static html file, for which Apache get the modification time right. (Last-Modified:Tue, 14 Oct 2014 15:10:37 GMT). the max-age=0 header is in the request sent by chrome when I type the URL and hit Enter. Is it there because of previous responses ? – zrz Oct 14 '14 at 17:43
  • I read that Chrome automatically adds Cache-Control:max-age=0 to request (except for the first time you load Chrome,type the URL, hit enter). But that doesn't seem to affect other servers (CDNs send 304 even with max-age=0 in the request). – zrz Oct 14 '14 at 18:37
  • @zrz: limiting intermediary caching is very useful when debugging, but otherwise would harm performance. Check the context of what you read on what chrome does. In terms of what apache does, it's quite configurable. Cache-control is an instruction for intermediary caches, not for the origin server. However, apache can act as an intermediary cache, and can be configured to do all sorts of things. I think if you take out your anti-caching instructions you'll get behaviour more like what you expect of an origin server. – mc0e Oct 16 '14 at 15:09
-1

If you have Apache configured with Cache-Control:No-cache, Apache will never send a HTTP 304 Not modified to the client.

If you want to revalidate some requests, put a Cache-Control:No-cache only on the pages where you need that. You don't need to revalidate all the resources, and you are wasting bandwidth by doing so.

ThoriumBR
  • 5,272
  • 2
  • 23
  • 34
  • I seem to be confused by the term "revalidate". To me, it means to check if it's a 304. Am I wrong ? – zrz Oct 14 '14 at 17:48
  • You are wrong. Revalidate is to send the data all again to the client and force him read everything again even if it already have the same information. You are basically disabling the cache on every client. – ThoriumBR Oct 14 '14 at 17:50
  • That explains a lot. Last thing I need explained having that in mind is that Apache sends 304 for some resources (png for example), while I still have that Cache-Control set no No-cache in the response and to max-age=0 in the request. Any clue ? – zrz Oct 14 '14 at 17:59
  • @ThoriumBR If I've interpreted you correctly, both of your answers are incorrect here; no-cache (as opposed to no-store) does not mean "don't cache", and may result in a 304 if content hasn't changed. Indeed the OP expected this but wasn't getting it due to the etag issue. must-revalidate relates to how stale content is handled and does not always send "the data all again". – Nick Feb 26 '17 at 17:22