14

Using Apache 2.4 on Debian 8.2, I am trying to enable caching of all css and js files. Caching of images works fine; that is, the browser receives a 304 status, so it doesn't download again. But I cannot get caching of other files working.

I use this inside a virtual host file:

<IfModule mod_expires.c>
    <FilesMatch "\.(jpe?g|png|gif|js|css)$">
        ExpiresActive On
        ExpiresDefault "access plus 1 week"
    </FilesMatch>
</IfModule>

The expires module is enabled. I did restart apache, cleaned browser cookies, etc. No success.

The response for a gif image, from browser developer tools:

Cache-Control:max-age=604800
Connection:Keep-Alive
Date:Wed, 25 Nov 2015 21:37:50 GMT
ETag:"4174a-4e69c97fbf080"
Expires:Wed, 02 Dec 2015 21:37:50 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.10 (Debian)

The response for a css file:

Accept-Ranges:bytes
Cache-Control:max-age=604800
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:135
Content-Type:text/css
Date:Wed, 25 Nov 2015 21:37:50 GMT
ETag:"5116-525639d271c78-gzip"
Expires:Wed, 02 Dec 2015 21:37:50 GMT
Keep-Alive:timeout=5, max=99
Last-Modified:Wed, 25 Nov 2015 20:50:52 GMT
Server:Apache/2.4.10 (Debian)
Vary:Accept-Encoding

It looks like the expires heading is set correctly, but the browser keeps requesting the file (200 OK).

I tried with Chrome and Firefox.

Summary:

1.) When I follow links inside the web site, the browser uses the cached files. But when I press F5, they re-download the css and js files, but they don't re-download images. Images give 304. That is fine.

2.) When I press Ctrl-F5, naturally enough, all files are re-downloaded. That's fine too.

3.) So the problem is how to enable caching (just like images) for other files. Why is apache discriminating between images and other files? I didn't put anything special to images in the config files.

Q: How to properly enable caching of css and js files?

Another Q: is there a special http header that says to the browser never to request the file. The reason is, sending even a request to check if the file is modified takes 100-200 ms, which is too much. I am sure the files will not be modified. And if they are modified, I can easily put a version string at the end of the css file, such as myFile.css?v=1.1 So I hope there should be a way to stop sending requests completely.

SOLVED

First, there is a bug in apache as mentioned in the answer below.

Second, there was a misunderstanding on my part. I guess this is how modern browsers work:

1.) Follow links inside a web site: No request is sent, even to check if the file has been modified.

2.) F5: Send a request. If file is not modified then the server responds 304.

3.) Ctrl+F5: Full download.

The behavior about F5 does not make sense to me. Anyway.

In case anybody needs it, here is a working solution that I put into virtual host file:

RequestHeader  edit "If-None-Match" "^\"(.*)-gzip\"$" "\"$1\""
Header  edit "ETag" "^\"(.*[^g][^z][^i][^p])\"$" "\"$1-gzip\""

LoadModule expires_module /usr/lib/apache2/modules/mod_expires.so
ExpiresActive On

<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
    ExpiresDefault "access plus 4 weeks"
</FilesMatch>

2 Answers 2

3

Turn off Etags, they don't play well in Apache when gzip is on for 304s.

See here: Apache is not sending 304 response (if mod_deflate and AddOutputFilterByType is enabled)

As images are already compressed they are typically not gzipped and hence why they work.

ETags are not that useful in my opinion in their current implementation (see my blog here for a more in depth discussion as to why) so, coupled with above bug, I turn them off.

For your second question just set a long expiry.

As discussed in the comments below there are three scenarios:

  1. Normal browsing - in which caching should be used and 304s only used if cache is still valid after expiry (in which case it's set to valid again for same expiry).

  2. F5 or Refresh button. This is an explicit action by the user to confirm the page and all its resources are still valid so they all will be double checked (even those still in cache and still valid according to expiries header) and 304s sent when they haven't changed. It does not mean "just redownload anything which has expired but leave cached items alone as they are still valid" as you think it should. Personally I think the current implementation the browsers use makes sense and your method would be confusing to end users. While some sites may version assets like images, css and JavaScript so rechecking is a waste of time, not all such sites do this.

  3. Ctrl+F5. This is a force refresh. It means "Ignore cache and download everything". It's rarely needed except by developers who change files requested on development servers.

Hope that all makes sense.

Edit 12 May 2016: Looks like Firefox is bringing in the functionality you actually want: https://bitsup.blogspot.ie/2016/05/cache-control-immutable.html?m=1

Sign up to request clarification or add additional context in comments.

7 Comments

Why only partially? And I'm not aware of browsers using HEAD requests. They wouldn't make much sense as would have to be followed up with a full request so they just use a conditional GET request and do it all in one go.
F5 does a manual refresh to check for any updates despite cache - so sends a conditional GET, so if file is not modified you get a 304 (ignoring Apache bugs). CTRL+F5 says do a full GET - even if you have a file in your cache and it's still valid so you should never get a 304. CTRL+F5 is useful when you believe cache is wrong (e.g. You reverted a file back to previous version on server so despite last modified not being after you still want to download it).
Why bother refreshing if you know it won't be different? :-) I'm guessing you're thinking of the scenario where the page HTML might be different (and let's assume not cached) but images won't be different (and are cached) so you'd prefer it to just download the page HTML? Well that's not how it works - F5 means "Check everything to see what, if anything, needs refreshing". I suppose browsers could implement a light version (e.g. Alt-F5) to mean "Refresh expired resources only" kind of like when you browse to that page again - but probably more confusing than it's worth to have 3 refresh types.
You've got to think it from the users perspective (since they are the one pressing the F5 button), rather than from the server side. F5 is an explicit action by a user saying "I'm not sure this page is the latest version - browser please check it for me again." Whether the expiries header is set is irrelevant - the user is asking the browser to double check. And 304 is the method to confirm that double check without the full cost of a download when the check proves that the file is still current. This is different to just browsing around when the expiries headers should be used as appropriate.
Amended my answer btw. While I understand your point I still think F5 means "check and refresh what's necessary" and your definition would be confusing to average user. So yes checking can take time for a site with lots of assets that don't change but then I'd argue that's the sites responsibility to code better! Remember regular browsers are the main visitors (and will suffer for such sites) and F5-ers are edge cases and you can make that simple (always refresh the page) but slow, or complex (only refresh what probably has changed) but faster. For edge cases simple wins for me every time.
|
1

If nothing else seems to work, don't forget to turn the disable cache from devtools in you browser!!!

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.