diff --git a/book/http_cache.rst b/book/http_cache.rst index 46e80ed4e73..e6903692dc8 100644 --- a/book/http_cache.rst +++ b/book/http_cache.rst @@ -328,7 +328,14 @@ its creation more manageable:: // set a custom Cache-Control directive $response->headers->addCacheControlDirective('must-revalidate', true); -Public vs private Responses +.. tip:: + + If you need to set cache headers for many different controller actions, + you might want to look into the FOSHttpCacheBundle_. It provides a way + to define cache headers based on the URL pattern and other request + properties. + +Public vs Private Responses ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Both gateway and proxy caches are considered "shared" caches as the cached @@ -393,9 +400,10 @@ header when none is set by the developer by following these rules: ``private`` directive automatically (except when ``s-maxage`` is set). .. _http-expiration-validation: +.. _http-expiration-and-validation: -HTTP Expiration and Validation ------------------------------- +HTTP Expiration, Validation and Invalidation +-------------------------------------------- The HTTP specification defines two caching models: @@ -412,7 +420,9 @@ The HTTP specification defines two caching models: header) to check if the page has changed since being cached. The goal of both models is to never generate the same response twice by relying -on a cache to store and return "fresh" responses. +on a cache to store and return "fresh" responses. To achieve long caching times +but still provide updated content immediately, *cache invalidation* is +sometimes used. .. sidebar:: Reading the HTTP Specification @@ -766,7 +776,7 @@ at some interval (the expiration) to verify that the content is still valid. annotations. See the `FrameworkExtraBundle documentation`_. .. index:: - pair: Cache; Configuration + pair: Cache; Configuration More Response Methods ~~~~~~~~~~~~~~~~~~~~~ @@ -794,8 +804,110 @@ Additionally, most cache-related HTTP headers can be set via the single )); .. index:: - single: Cache; ESI - single: ESI + single: Cache; Invalidation + +.. _http-cache-invalidation: + +Cache Invalidation +~~~~~~~~~~~~~~~~~~ + + "There are only two hard things in Computer Science: cache invalidation + and naming things." -- Phil Karlton + +Once an URL is cached by a gateway cache, the cache will not ask the +application for that content anymore. This allows the cache to provide fast +responses and reduces the load on your application. However, you risk +delivering outdated content. A way out of this dilemma is to use long +cache lifetimes, but to actively notify the gateway cache when content +changes. Reverse proxies usually provide a channel to receive such +notifications, typically through special HTTP requests. + +.. caution:: + + While cache invalidation is powerful, avoid it when possible. If you fail + to invalidate something, outdated caches will be served for a potentially + long time. Instead, use short cache lifetimes or use the validation model, + and adjust your controllers to perform efficient validation checks as + explained in :ref:`optimizing-cache-validation`. + + Furthermore, since invalidation is a topic specific to each type of reverse + proxy, using this concept will tie you to a specific reverse proxy or need + additional efforts to support different proxies. + +Sometimes, however, you need that extra performance you can get when +explicitly invalidating. For invalidation, your application needs to detect +when content changes and tell the cache to remove the URLs which contain +that data from its cache. + +.. tip:: + + If you want to use cache invalidation, have a look at the + `FOSHttpCacheBundle`_. This bundle provides services to help with various + cache invalidation concepts, and also documents the configuration for the + a couple of common caching proxies. + +If one content corresponds to one URL, the ``PURGE`` model works well. +You send a request to the cache proxy with the HTTP method ``PURGE`` (using +the word "PURGE" is a convention, technically this can be any string) instead +of ``GET`` and make the cache proxy detect this and remove the data from the +cache instead of going to Symfony to get a response. + +Here is how you can configure the Symfony reverse proxy to support the +``PURGE`` HTTP method:: + + // app/AppCache.php + + // ... + use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Response; + + class AppCache extends HttpCache + { + protected function invalidate(Request $request, $catch = false) + { + if ('PURGE' !== $request->getMethod()) { + return parent::invalidate($request, $catch); + } + + if ('127.0.0.1' !== $request->getClientIp()) { + return new Response('Invalid HTTP method', Response::HTTP_BAD_REQUEST); + } + + $response = new Response(); + if ($this->getStore()->purge($request->getUri())) { + $response->setStatusCode(200, 'Purged'); + } else { + $response->setStatusCode(200, 'Not found'); + } + + return $response; + } + } + +.. caution:: + + You must protect the ``PURGE`` HTTP method somehow to avoid random people + purging your cached data. + +**Purge** instructs the cache to drop a resource in *all its variants* +(according to the ``Vary`` header, see above). An alternative to purging is +**refreshing** a content. Refreshing means that the caching proxy is +instructed to discard its local cache and fetch the content again. This way, +the new content is already available in the cache. The drawback of refreshing +is that variants are not invalidated. + +In many applications, the same content bit is used on various pages with +different URLs. More flexible concepts exist for those cases: + +* **Banning** invalidates responses matching regular expressions on the + URL or other criteria; +* **Cache tagging** lets you add a tag for each content used in a response + so that you can invalidate all URLs containing a certain content. + +.. index:: + single: Cache; ESI + single: ESI .. _edge-side-includes: @@ -1040,67 +1152,6 @@ The ``render_esi`` helper supports two other useful options: to the ESI with a value of ``continue`` indicating that, in the event of a failure, the gateway cache will simply remove the ESI tag silently. -.. index:: - single: Cache; Invalidation - -.. _http-cache-invalidation: - -Cache Invalidation ------------------- - - "There are only two hard things in Computer Science: cache invalidation - and naming things." -- Phil Karlton - -You should never need to invalidate cached data because invalidation is already -taken into account natively in the HTTP cache models. If you use validation, -you never need to invalidate anything by definition; and if you use expiration -and need to invalidate a resource, it means that you set the expires date -too far away in the future. - -.. note:: - - Since invalidation is a topic specific to each type of reverse proxy, - if you don't worry about invalidation, you can switch between reverse - proxies without changing anything in your application code. - -Actually, all reverse proxies provide ways to purge cached data, but you -should avoid them as much as possible. The most standard way is to purge the -cache for a given URL by requesting it with the special ``PURGE`` HTTP method. - -Here is how you can configure the Symfony reverse proxy to support the -``PURGE`` HTTP method:: - - // app/AppCache.php - - // ... - use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\Response; - - class AppCache extends HttpCache - { - protected function invalidate(Request $request, $catch = false) - { - if ('PURGE' !== $request->getMethod()) { - return parent::invalidate($request, $catch); - } - - $response = new Response(); - if ($this->getStore()->purge($request->getUri())) { - $response->setStatusCode(200, 'Purged'); - } else { - $response->setStatusCode(404, 'Not purged'); - } - - return $response; - } - } - -.. caution:: - - You must protect the ``PURGE`` HTTP method somehow to avoid random people - purging your cached data. - Summary ------- @@ -1128,3 +1179,4 @@ Learn more from the Cookbook .. _`P6 - Caching: Browser and intermediary caches`: http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache .. _`FrameworkExtraBundle documentation`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/cache.html .. _`ESI`: http://www.w3.org/TR/esi-lang +.. _`FOSHttpCacheBundle`: http://foshttpcachebundle.readthedocs.org/