I am trying to cache a (javascript) resource in the browser and have properly set all of Cache-control:max-age, Expires, and Etag in the response headers (as is seen from the screenshot).
The browser requests with "if-none-match" and "if-modified-since", and in both cases the conditions are met:
So I should get response 304, right? But no, I keep getting 200 OK, which means that apache keeps serving the file (albeit compressed) every time. Tested with Firefox, Chrome, curl -- no use. Server always serves the whole file, even if I am not asking it to...
Using curl, I have traced the problem to gzip & Etag:
Here is the request/response:
Request Headers 00:09:12.000
Response Headers Δ1100ms
Apache mod_deflate
is creating unique Etag for each entity as these identify
the specific entity variant of the URL. Each negotiated variant needs to have unique ETag:s. For mod_deflate
it's as simple as adding the encoding to the already computed ETag.
One workaround is to remove the encoding from the Etag:
<Location /js>
RequestHeader edit "If-None-Match" "^(.*)-gzip$" "$1"
Header edit "ETag" "^(.*[^g][^z][^i][^p])$" "$1-gzip"
</Location>
If you are using Apache 2.5 with the mod_deflate
module, you can use the directive DeflateAlterETag
to specifies how the ETag hader should be altered when a response is compressed.
DeflateAlterETag AddSuffix|NoChange|Remove
Source: https://httpd.apache.org/docs/trunk/mod/mod_deflate.html#deflatealteretag
This blog post suggest to remove Etags altogether and to rely on the Cache-Control
header.
To do that in httpd.conf
:
<IfModule mod_headers.c>
Header unset ETag
</IfModule>
FileETag None
Note that if entities gzip:ed by mod_deflate
still carries the same ETag as the plain entiy, this may cause inconsistency in ETag aware proxy caches.
More info here: