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:
A workaround not yet reported is, you can just apply this configuration:
RequestHeader edit "If-None-Match" '^"((.*)-gzip)"$' '"$1", "$2"'
(Originally suggested by Joost Dekeijzer, see https://bz.apache.org/bugzilla/show_bug.cgi?id=45023#c22, and still working nowadays on version 2.4)
There also seems to be a problem with gzipped resources like .js .css and the Vary: Accept-encoding Header with Chrome.
Please check my Anwser given here: https://stackoverflow.com/a/40726246/135785
This solved the problem for me:
<FilesMatch "(\.js\.gz|\.css\.gz)$">
# Serve correct encoding type.
Header set Content-Encoding gzip
# Force proxies to cache gzipped & non-gzipped css/js files separately.
BrowserMatch "Chrome" ChromeFound
Header append Vary Accept-Encoding env=!ChromeFound
</FilesMatch>
Check your Apache Config for "Header append Vary Accept-Encoding"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With