cache_control

The configuration contains a number of rules. When a request matches the parameters described in the match section, the headers as defined under headers will be set on the response, if they are not already set. Rules are checked in the order specified, where the first match wins.

A global setting and a per rule overwrite option allow to overwrite the cache headers even if they are already set:

# app/config/config.yml
fos_http_cache:
    cache_control:
        defaults:
            overwrite: false
        rules:
            # only match login.example.com
            -
                match:
                    host: ^login.example.com$
                headers:
                    overwrite: true
                    cache_control:
                        public: false
                        max_age: 0
                        s_maxage: 0
                    etag: true
                    vary: [Accept-Encoding, Accept-Language]

            # match all actions of a specific controller
            -
                match:
                    attributes: { _controller: ^Acme\\TestBundle\\Controller\\DefaultController::.* }
                headers:
                    cache_control:
                        public: true
                        max_age: 15
                        s_maxage: 30
                    last_modified: "-1 hour"

            -
                match:
                    path: ^/$
                headers:
                    cache_control:
                        public: true
                        max_age: 64000
                        s_maxage: 64000
                    etag: true
                    vary: [Accept-Encoding, Accept-Language]

            # match everything to set defaults
            -
                match:
                    path: ^/
                    additional_response_status:
                        - 500
                headers:
                    cache_control:
                        public: true
                        max_age: 15
                        s_maxage: 30
                    etag: true

rules

type: array

A set of cache control rules consisting of match criteria and header instructions.

match

type: array

A match definition that when met, will execute the rule effect. See match.

The cache control rules additionally allow to overwrite the global cacheable configuration for a specific rule. Put the match_response (semantics of response.expression) or additional_response_status setting under match with the same semantics as explained in cacheable.

Be aware that additional_response_status completely replaces cacheable.response.additional_status. There is no merge taking place.

headers

type: array

In the headers section, you define what headers to set on the response if the request was matched.

Headers are merged. If the response already has certain cache directives set, they are not overwritten. The configuration can thus specify defaults that may be changed by controllers or services that handle the response, or @Cache annotations.

The listener that applies the rules is triggered at priority 10, which makes it handle before the @Cache annotations from the SensioFrameworkExtraBundle are evaluated. Those annotations unconditionally overwrite cache directives.

The only exception is responses that only have the no-cache directive. This is the default value for the cache control and there is no way to determine if it was manually set. If the full header is only no-cache, the whole cache control is overwritten.

You can prevent the cache control on specific controller actions by calling FOS\HttpCacheBundle\EventListener\CacheControlListener::setSkip(). When skip is set to true, no cache rules are applied. This service can be autowired - in older versions of the bundle, use the service fos_http_cache.event_listener.cache_control.

cache_control

type: array

The map under cache_control is set in a call to Response::setCache(). The names are specified with underscores in yaml, but translated to - for the Cache-Control header.

You can use the standard cache control directives:

  • max_age time in seconds;

  • s_maxage time in seconds for proxy caches (also public caches);

  • private true or false;

  • public true or false;

  • no_cache true or false (use exclusively to support HTTP 1.0);

  • no_store: true or false.

# app/config/config.yml
fos_http_cache:
    cache_control:
        rules:
            -
                headers:
                    cache_control:
                        public: true
                        max_age: 64000
                        s_maxage: 64000

If you use no_cache, you should not set any other options. This will make Symfony properly handle HTTP 1.0, setting the Pragma: no-cache and Expires: -1 headers. If you add other cache_control options, Symfony will not do this handling. Note that Varnish 3 does not respect no-cache by default. If you want it respected, add your own logic to vcl_fetch.

Note

The cache-control headers are described in detail in RFC 2616#section-14.9 and further clarified in RFC 7234#section-5.2.

Extra Cache Control Directives

You can also set headers that Symfony considers non-standard, some coming from RFCs extending RFC 2616 HTTP/1.1. The following options are supported:

The stale directives need a parameter specifying the time in seconds how long a cache is allowed to continue serving stale content if needed. The other directives are flags that are included when set to true:

# app/config/config.yml
fos_http_cache:
    cache_control:
        rules:
            -
                path: ^/$
                headers:
                    cache_control:
                        stale_while_revalidate: 9000
                        stale_if_error: 3000
                        must_revalidate: true
                        proxy_revalidate: true
                        no_transform: true

etag

type: enum options: false, "strong", "weak"

This enables a simplistic ETag calculated as md5 hash of the response body:

New in version 2.2: You can set up ETag to be strong or weak by setting the option to “strong” or “weak” respectively.

# app/config/config.yml
fos_http_cache:
    cache_control:
        rules:
            -
                headers:
                    etag: "strong"

Tip

This simplistic ETag handler will not help you to prevent unnecessary work on your web server, but allows a caching proxy to use the ETag cache validation method to preserve bandwidth. The presence of an ETag tells clients that they can send a If-None-Match header with the ETag their current version of the content has. If the caching proxy still has the same ETag, it responds with a “304 Not Modified” status.

You can get additional performance if you write your own ETag handler that can read an ETag from your content and decide very early in the request whether the ETag changed or not. It can then terminate the request early with an empty “304 Not Modified” response. This avoids rendering the whole page. If the page depends on permissions, make sure to make the ETag differ based on those permissions (e.g. by appending the user context hash).

You want to set weak ETag when you are using gzip compression on web server. Because while strong ETag means that entity is byte-to-byte identical, weak ETag means semantically equivalent entities. See: RFC 2616#section-13.3.3 that describes weak and strong validation.

last_modified

type: string

The input to the last_modified is used for the Last-Modified header. This value must be a valid input to DateTime:

# app/config/config.yml
fos_http_cache:
    cache_control:
        rules:
            -
                headers:
                    last_modified: "-1 hour"

Note

Setting an arbitrary last modified time allows clients to send If-Modified-Since requests. Varnish can handle these to serve data from the cache if it was not invalidated since the client requested it.

Note that the default system will generate an arbitrary last modified date. You can get additional performance if you write your own last modified handler that can compare this date with information about the content of your page and decide early in the request whether anything changed. It can then terminate the request early with an empty “304 Not Modified” response. Using content meta data increases the probability for a 304 response and avoids rendering the whole page.

See also RFC 7232#section-2.2.1 for further consideration on how to generate the last modified date.

Note

You may configure both ETag and last modified on the same response. See RFC 7232#section-2.4 for more details.

vary

type: string

You can set the vary option to an array that defines the contents of the Vary header when matching the request. This adds to existing Vary headers, keeping previously set Vary options:

# app/config/config.yml
fos_http_cache:
    cache_control:
        rules:
            -
                headers:
                    vary: My-Custom-Header

reverse_proxy_ttl

type: integer

Set a X-Reverse-Proxy-TTL header for reverse proxy time-outs not driven by s-maxage. This keeps your s-maxage free for use with reverse proxies not under your control.

Warning

This is a custom header. You need to set up your caching proxy to respect this header. See the FOSHttpCache documentation for Varnish or for the Symfony HttpCache.

To use the custom TTL, specify the option reverse_proxy_ttl in the headers section:

# app/config/config.yml
fos_http_cache:
    cache_control:
        rules:
            -
                headers:
                    reverse_proxy_ttl: 3600
                    cache_control:
                        public: true
                        s_maxage: 60

This example adds the header X-Reverse-Proxy-TTL: 3600 to your responses.