Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure ETag with browser caching

I’ve setup a browser cache for a static site via the .htaccess file by setting:

# BROWER CACHING - 1 Day for images
<filesMatch ".(jpg|jpeg|gif|ico)$">
Header set Cache-Control "max-age=86400, public"
</filesMatch>

I’m fine with these images having a 1 day cache, but the site changes frequently and thus I don’t want to cache the CSS and JS files.

I’ve read about ETag, which, as I understand, allows you to cache a file, but also set its creation date, so if it gets updated the next time a client visits the site, it will check if the creation date matches.

  1. Have I understood ETag correctly?
  2. How do I configure it? I’ve looked around, but couldn’t find any info on its configuration.
like image 331
sam Avatar asked May 16 '16 22:05

sam


3 Answers

You would use either FileETag MTime Size or Header unset Etag and FileEtag none. Do not use both (Create ETag and Remove ETag) and only choose which one works best on your particular server.

# Create the ETag (entity tag) response header field
FileETag MTime Size

or

# Remove the ETag (entity tag) response header field
Header unset ETag
FileETag none
like image 75
Ed-AITpro Avatar answered Oct 21 '22 03:10

Ed-AITpro


HTTP has several features related to caching and they apply to both user agent (browser) cache and proxy caches (whether transparent, or not; e.g. proxy in the client’s network or a reverse proxy sitting just next to the server). These features come in two groups: expiration (may prevent request entirely) and validation (may prevent transfer of data).

Entity tag (ETag) is just one of these features and belongs to the validation group. The other one in this group is last modification time (Last-Modified). Entity tag allows for cache invalidation due to contents change instead of newer last modification time. Read more on how entity tag works on Wikipedia. In short, the typical usage is:

  1. The server adds ETag header to a response containing a resource being served.

  2. The client caches the resource and remembers its entity tag (the value of ETag).

  3. Next time the client needs the resource, it requests it from the server conditionally. In the request, it includes If-None-Match header containing the entity tag.

  4. If the resource changed (the entity tag in If-None-Match is considered to be stale by the server), the server sends a response containing the current version of the resource (and the new entity tag), otherwise it just responds with 304 Not Modified and does not bother to send the resource again.

For static files (not created dynamically by a CGI script or so, on each request), Apache may be configured to generate ETag via FileETag directive. By default, without you making any changes to the configuration, Apache will generate ETag and its value will be based on the file’s last modification time (mtime) and size in Apache 2.4. In Apache 2.3.14, the default used to include the file’s inode number, too.

If the file is served dynamically, Apache cannot generate the ETag, because it does not know the details of how the resource to be cached is generated. It is up to the script to set ETag appropriately and to handle the If-None-Match. E.g. in mod_perl, the If-None-Match part can be handled using Apache2::Request::meets_conditions, which implements handling of HTTP/1.1 conditional requests in general.

If you want to rely solely on ETag, you have to disable other validation features and the expiration mechanism. Set Cache-Control: max-age=0, must-revalidate and Expires: 0 to force the revalidation of cache entries (i.e. always make a request). You may also remove the Last-Modified header from the responses, but HTTP/1.1 advises against that, in general.

For comparison of Last-Modified and ETag, see these:

  • if-modified-since vs if-none-match @ SO
  • Getting ETags right

Note that Last-Modified is seen as a HTTP/1.0 compatibility feature. ETag may contain the same value and work exactly the same (except using If-None-Match instead of If-Modified-Since).

As a side note, I’d like to add that proposed standard RFC 7232 exists and it is related to details of entity tags and conditional requests. See its appendix A for changes it introduces from HTTP/1.1.

like image 22
Palec Avatar answered Oct 21 '22 01:10

Palec


ETAG is not the most important attribute. The main attribute you're missing is expires. I'm 100% percent sure, browser cache will work without etag. Check the below configuration on http://pisrs.si. How to check? Hit F12 in browser, goto network tab, see how resources are fetched, compare to your site. Localhost resources are cached in different way. Check your browser info on that.

Below is working configuration from main domain, that is working. Make sure you have the necessary mods enabled.

<IfModule mod_mime.c>
    AddType text/css .css
    AddType application/x-javascript .js
    AddType image/bmp .bmp
    AddType image/gif .gif
    AddType application/x-gzip .gz .gzip
    AddType image/x-icon .ico
    AddType image/jpeg .jpg .jpeg .jpe
    AddType image/png .png
    AddType application/x-font-ttf .ttf .ttc
    AddType application/zip .zip
</IfModule>
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css A31536000
    ExpiresByType application/x-javascript A31536000
    ExpiresByType application/javascript A31536000
    ExpiresByType text/javascript A31536000
    ExpiresByType text/x-js A31536000
    ExpiresByType image/bmp A31536000
    ExpiresByType image/gif A31536000
    ExpiresByType application/x-gzip A31536000
    ExpiresByType image/x-icon A31536000
    ExpiresByType image/jpeg A31536000
    ExpiresByType application/x-font-otf A31536000
    ExpiresByType image/png A31536000
    ExpiresByType application/x-font-ttf A31536000
    ExpiresByType application/zip A31536000
</IfModule>
<IfModule mod_deflate.c>
    <IfModule mod_headers.c>
        Header append Vary User-Agent env=!dont-vary
    </IfModule>
        AddOutputFilterByType DEFLATE text/html text/css text/x-component application/x-javascript application/javascript text/javascript text/x-js text/plain image/x-icon image/png image/gif
    <IfModule mod_mime.c>
        # DEFLATE by extension
        AddOutputFilter DEFLATE js css htm html xml png gif
    </IfModule>
</IfModule>
<FilesMatch "\.(gif|ico|jpg|jpeg|png|GIF|ICO|JPG|JPEG|PNG|css|js|woff|CSS|JS|WOFF|ttf|TTF)$">
    <IfModule mod_headers.c>
         Header unset Set-Cookie
         Header set Cache-Control "max-age=31536000, public"
    </IfModule>
</FilesMatch>
like image 40
Mitja Gustin Avatar answered Oct 21 '22 02:10

Mitja Gustin