I have the following code in my .htaccess file:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
</IfModule>
This means that jpg and jpeg images should have a cache expiration date of 1 year. The response headers in Chrome's DevTools Console reflect that.
content-type:image/jpeg
date:Mon, 07 Nov 2016 04:05:46 GMT
expires:Tue, 07 Nov 2017 04:05:46 GMT
last-modified:Sun, 06 Nov 2016 18:40:41 GMT
However, on PageSpeed insights, the recommendations show that the cache is only valid for 5 hours and I should increase that time. Why is that?
You should use the newer Cache-Control header:
Cache-Control: max-age=<some-time-in-seconds>, public
The old HTTP/1 Expires header is imprecise and causes problems when intermediate caches are involved.
Google PageSpeed probably assumes that it will not be respected by browsers. In that case the browser reverts to so called heuristic caching where the expiration is typically calculated as a fraction (e.g. 20%) of the difference between the Last-Modified date and now - which would yield a value similar to the one you saw.
Related
I have used GTMetrix to test my site performance. Overall score is not that bad (93%) but there are some things that can be improved. One of the lowest scores I got is leverage browser caching. None of my CSS/JS/IMAGE files do not have expiration date set. I'm not familiar with leverage caching and how expiration can be set. After looking around I see that people use .htaccess file. I'm not sure where to create that file and what to add in the file in order to set expiration time/period. Here is example of my header files:
https://example.org/CSS/Login.css (expiration not specified)
https://example.org/JS/Login.js (expiration not specified)
https://example.org/animated_favicon1.gif (expiration not specified)
https://example.org/favicon.ico (expiration not specified)
https://example.com/images/basicrecblue.gif (expiration not specified)
https://example.com/siteseal/javascript/siteseal.js (expiration not specified)
The files above were identified with GTmetrix test. Can anyone help with some example on to implement .htaccess file? How to set expiration for each file type? I use ColdFusion on the back end and JS, HTML5 and Css with Bootstrap on the front end.
Assuming you are using Apache HTTPD as your webserver, you can simply set the cache control using the mod_expires module.
You can place instructions either globally using the config or for specific virtual hosts using .htaccess files. The content should look like:
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 30 seconds"
ExpiresByType text/html "access plus 15 days"
ExpiresByType image/jpg "access plus 1 months"
ExpiresByType image/png "access plus 1 months"
ExpiresByType application/javascript "access plus 1 months"
</IfModule>
Note that you might have to install/enable mod_expires first. You can find further instructions all around the internet.
Im pretty new to scripting and coding. I have now picked an interest in speeding up my website. To do this i would like to begin leveraging browser caching.
I've read up on a couple of things but i'm now struggeling to make the right decision.
As far as i understand there are three options:
-expires
-max age
-Etag (while using max age)
The first two are not suitable for an e-commerce website (opencart btw) in my opinion. But are far easier to implement than the Etag as i understand.
I got as far as getting the expire and max age working in my testing eviroment but then i get problems with outdated client side rendering of my webpage.
So in conclusion i wanna go for the Etag but i have no clue where to start! Is there anyone (maybe with opencart experience aswell?) who can help me get on the way?
Thanks in advance!
Regards,
George
ETags are not that complicated to implement. Here's a snippet of code for your .htaccess file that will enable ETags for your images and other files that don't change that often:
# ETags Settings (for Cache purposes)
<ifModule mod_headers.c>
<FilesMatch \.(?i:jpeg|jpg|gif|png|css|js|xml)$>
FileETag MTime Size
</FilesMatch>
<FilesMatch \.(?i:php)$>
Header unset ETag
Header set Cache-Control "max-age=0, private, no-store, no-cache, must-revalidate"
Header set Pragma "no-cache"
FileETag None
</FilesMatch>
</ifModule>
# Expires Settings
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 month"
# Images
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
</IfModule>
Just a little background (though I'm sure you already know) and explanation:
ETags are more reliable than expires due to the fact that browsers that honor the expire directive will not change the image/file for the lifetime it is given, regardless if there are any changes. However ETags can be configured to indicate a browser when to change the image.
In the code provided above FileETag MTime Size will have browser updating the images, css, js and xml files (the ?i: is to do a case-insensitive match) if there are any changes in size or modification time. And the best part: it supersedes expires directives!
Also, the code above will disable ETags for php files due to the dynamic nature of the content.
I included the expires directives for images because, at the time of me writing this, many speed checkers and validators will rank you a little bit down for not having them, even if ETags are set.
I currently have this in my htaccess.
<IfModule mod_headers.c>
Header set Cache-Control 's-maxage=604800'
</IfModule>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html A86400
</IfModule>
HTTP headers will show as...
Cache-Control: s-maxage=604800
Cache-Control: max-age=86400
Expires: Wed, 18 Dec 2013 03:51:18 GMT
How do I merge s-maxage and max-age so that it will show as:
Cache-Control: max-age=86400, s-maxage=604800
I've tried using Header set, append, merge and add but nothing works. It seems that ExpiresActive On will automatically include Cache-Control: max-age to the headers.
According to the manual, ordering is important. Try re-ordering the two directives and using merge to prevent any duplicates:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html A86400
</IfModule>
<IfModule mod_headers.c>
Header merge Cache-Control 's-maxage=604800'
</IfModule>
If you use Header edit you can add the s-maxage header depending on the max-age header:
ExpiresByType text/html A86400
ExpiresByType text/xml A86401
Header edit Cache-Control ^(max-age=86400)$ "$1; s-maxage=604800"
Result: s-maxage is only added for text/html
The simple answer is that there may not be an easy way to join your two headers, but it doesn't actually matter. Semantically there is no difference between this form:
Cache-Control: s-maxage=604800
Cache-Control: max-age=86400
and this form:
Cache-Control: s-maxage=604800, max-age=86400
RFC 7234 § 5.2 defines the Cache-Control header field value as a list of directives defined in a specific form:
Cache-Control = 1#cache-directive
cache-directive = token [ "=" ( token / quoted-string ) ]
That form is subject to this HTTP rule from RFC 2616 § 4.2:
Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma. The order in which header fields with the same field-name are received is therefore significant to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of these field values when a message is forwarded.
(Note that the #(values) grammar is defined in § 2.1)
Therefore, if a client is treating those two varieties differently, it is in violation of HTTP/1.1.
In fact, there is a chance that what you are seeing as two headers is actually being sent to the client as a single conjoined header line, but your viewer or output is keeping the directives split into two for display.
Following the advice given by Yahoo / YSlow at http://developer.yahoo.com/performance/rules.html#expires I am trying to set a far future Expires header for my images.
In my .htacess I have:
<filesMatch "\.(jpg|jpeg|png|gif)$">
Header unset Pragma
FileETag None
Header unset ETag
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2014 20:00:00 GMT"
Header unset Last-Modified
</filesMatch>
Using Live HTTP Headers in Firefox I can see that there is no ETag and the Expires date shows as 2014. Also, looking at the cache I can confirm the Expires date and that there is no ETag or Server Last Modified date.
Again following the information given at YSlow I was expecting that if I now alter an image without altering its filename no changes would take effect until the Expires date is reached. YSlow points out that “if you use a far future Expires header you have to change the component's filename whenever the component changes”.
However, testing on localhost with XAMPP any change I make to an image is still immediately reflected on the web page if I refresh it.
Is this a local server thing or have I misunderstood how this is intended to work?
Thanks.
I'd like to set the Expires header for js.gz files. I've added a .htaccess file to the directory containing these files. This is actually part of a widget I'm developing which I will be deployed across multiple domains, so I don't want to use any apache modules which might be inaccessible to my clients.
Header set Expires "Tue, 16 Jun 2020 20:00:00 GMT"
not with mod_expires
ExpiresActive On
I want to dynamically set the date to today's date plus 1 month.
Resolved in comments! Thanks fge
Uh, why not mod_expire?? It is designed for this job – fge