10

Craft seems to be setting headers to tell the browser not to cache anything it serves, which seems bad.

Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Why it do dat?

Tim Kelty
  • 3,081
  • 1
  • 18
  • 29

3 Answers3

10

Craft doesn't explicitly set any caching headers in the response, but you can control exactly how you want your caching headers to behave from your templates with the {% header %} tag.

For example:

{# Tell the browser to cache this page for 30 days #}
{% set expiry = now|date_modify('+30 days') %}

{% header "Cache-Control: max-age=" ~ expiry.timestamp %}
{% header "Pragma: cache" %}
{% header "Expires: " ~ expiry|date('D, d M Y H:i:s', 'GMT') ~ " GMT" %}

By default PHP has the session_cache_limiter() method set to nocache, which is probably what you're seeing.

Brad Bell
  • 67,440
  • 6
  • 73
  • 143
  • Hmmm...It seems like something is (Yii or Craft) unless I'm confused.

    Request headers for a static (non-craft request):

    Date: Thu, 18 Sep 2014 01:44:49 GMT
    Server: Apache
    Last-Modified: Thu, 18 Sep 2014 01:44:48 GMT
    Accept-Ranges: bytes
    Cache-Control: max-age=0
    Expires: Thu, 18 Sep 2014 01:44:49 GMT
    Vary: Accept-Encoding
    Content-Encoding: gzip
    X-UA-Compatible: IE=edge
    Content-Length: 26
    Keep-Alive: timeout=5, max=100
    Connection: Keep-Alive
    Content-Type: text/html; charset=utf-8```
    
    Here's one from Craft:
    
    – Tim Kelty Sep 18 '14 at 01:45
  • Maybe Apache sets them by default if nothing has already been set? – Brad Bell Sep 18 '14 at 01:49
  • Response header examples below (non-pertinent headers removed)

    Response headers for a static (non-Craft request):

    Date: Thu, 18 Sep 2014 01:44:49 GMT
    Last-Modified: Thu, 18 Sep 2014 01:44:48 GMT
    Cache-Control: max-age=0
    Expires: Thu, 18 Sep 2014 01:44:49 GMT
    

    Here's one from Craft:

    Max-Age=300; path=/
    Expires: Thu, 19 Nov 1981 08:52:00 GMT
    Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
    Pragma: no-cache
    
    – Tim Kelty Sep 18 '14 at 01:51
  • The only related header I've seen Apache set by default is Cache-Control: max-age=0 – Tim Kelty Sep 18 '14 at 01:52
  • If you look at craft/app/services/TemplateService->renderTemplate(), you can see the headers Craft will set when rendering a template. – Brad Bell Sep 18 '14 at 01:55
  • Maybe a php.ini thing? Really strange. – Brad Bell Sep 18 '14 at 01:55
  • http://php.net/manual/en/session.configuration.php#ini.session.cache-limiter – Brad Bell Sep 18 '14 at 01:59
  • Weird. I tested it by just bailing out of the top of index.php with an exit('Hello'); - no no-cache headers. Once I let Craft run though, I see them. Are you not seeing the Cache-Control/Pragma headers on your Craft installs? – Tim Kelty Sep 18 '14 at 04:59
  • For the hell of it I checked the response headers on http://straightupcraft.com/ and I see the same thing. – Tim Kelty Sep 18 '14 at 04:59
  • Right... because session_cache_limiter() kicks in as soon as PHP's session_start() gets called, which won't have happened at the top of the root index.php. Craft/Yii will call that as soon as HttpSessionService->init() gets invoked in a request. – Brad Bell Sep 18 '14 at 05:02
  • You're right :). Same result with this in index.php:
    session_start();
    exit('Sorry, Brad.);
    
    – Tim Kelty Sep 18 '14 at 05:12
  • So I suppose the moral of the story is... if you don't like the default behavior, you can change it in your php.ini file. :) – Brad Bell Sep 18 '14 at 05:14
  • Yep! Sorry for wasting your time.

    The whole reason this came up is I was playing around with Varnish w/ Craft and by default it bypasses when it gets a Cache-control: no-cache response.

    – Tim Kelty Sep 18 '14 at 05:17
  • Not a waste at all. We both learned something! – Brad Bell Sep 18 '14 at 05:19
  • 1
    @TimKelty I would definitely recommend not changing this from php.ini as it will have unintended consequences. If you don’t like PHP’s default behavior you should just start explicitly setting what you want using the {% header %} tag. – Brandon Kelly Sep 18 '14 at 13:50
  • 1
    Pfft... LIVE ON THE EDGE! – Brad Bell Sep 18 '14 at 18:05
2

As highlighted in Brad Bell's answer, those headers are likely set by PHP. By default PHP has the session_cache_limiter() method set to nocache. You can verify this in your Craft admin panel under Utilities > PHP Info > session.cache_limiter.

If you change this value to public, it will set a cache expiry according to the value of session.cache_expire (set to 180 by default). This is explained here in the PHP docs.

I did not heed Brandon Kelly's advice, and I set session.cache_limiter=public in my php.ini file. I do not know which unintended consequences he speaks of, but I like to live dangerously.

Here are the new headers I get:

Cache-Control: public, max-age=10800
Expires: Wed, 27 Nov 2019 11:54:38 GMT (180 minutes from now)

If you do this, it will break a few things in the admin. Admin pages won't always load properly because the wrong things will be cached. It works perfectly on the website though.

nicbou
  • 142
  • 7
0

This had me confused for a while: if you're using Craft Nitro, the Nginx config adds Cache-Control: no-store, no-cache ... headers which cannot by overridden from PHP or Twig.

In Nitro 1.x you could SSH into the machine and edit the Nginx config to not add the headers. I haven't been able to get Nitro 2.0 to work and have switched to Docker Compose which is simpler and doesn't have this caching problem.

Tamlyn
  • 183
  • 6