@@ -333,7 +333,14 @@ its creation more manageable::
333333 // set a custom Cache-Control directive
334334 $response->headers->addCacheControlDirective('must-revalidate', true);
335335
336- Public vs private Responses
336+ .. tip ::
337+
338+ If you need to set cache headers for many different controller actions,
339+ you might want to look into the FOSHttpCacheBundle _. It provides a way
340+ to define cache headers based on the URL pattern and other request
341+ properties.
342+
343+ Public vs Private Responses
337344~~~~~~~~~~~~~~~~~~~~~~~~~~~
338345
339346Both gateway and proxy caches are considered "shared" caches as the cached
@@ -399,9 +406,10 @@ header when none is set by the developer by following these rules:
399406 ``private `` directive automatically (except when ``s-maxage `` is set).
400407
401408.. _http-expiration-validation :
409+ .. _http-expiration-and-validation :
402410
403- HTTP Expiration and Validation
404- ------------------------------
411+ HTTP Expiration, Validation and Invalidation
412+ --------------------------------------------
405413
406414The HTTP specification defines two caching models:
407415
@@ -418,7 +426,9 @@ The HTTP specification defines two caching models:
418426 header) to check if the page has changed since being cached.
419427
420428The goal of both models is to never generate the same response twice by relying
421- on a cache to store and return "fresh" responses.
429+ on a cache to store and return "fresh" responses. To achieve long caching times
430+ but still provide updated content immediately, *cache invalidation * is
431+ sometimes used.
422432
423433.. sidebar :: Reading the HTTP Specification
424434
@@ -772,7 +782,7 @@ at some interval (the expiration) to verify that the content is still valid.
772782 annotations. See the `FrameworkExtraBundle documentation `_.
773783
774784.. index ::
775- pair: Cache; Configuration
785+ pair: Cache; Configuration
776786
777787More Response Methods
778788~~~~~~~~~~~~~~~~~~~~~
@@ -800,8 +810,110 @@ Additionally, most cache-related HTTP headers can be set via the single
800810 ));
801811
802812.. index ::
803- single: Cache; ESI
804- single: ESI
813+ single: Cache; Invalidation
814+
815+ .. _http-cache-invalidation :
816+
817+ Cache Invalidation
818+ ~~~~~~~~~~~~~~~~~~
819+
820+ "There are only two hard things in Computer Science: cache invalidation
821+ and naming things." -- Phil Karlton
822+
823+ Once an URL is cached by a gateway cache, the cache will not ask the
824+ application for that content anymore. This allows the cache to provide fast
825+ responses and reduces the load on your application. However, you risk
826+ delivering outdated content. A way out of this dilemma is to use long
827+ cache lifetimes, but to actively notify the gateway cache when content
828+ changes. Reverse proxies usually provide a channel to receive such
829+ notifications, typically through special HTTP requests.
830+
831+ .. caution ::
832+
833+ While cache invalidation is powerful, avoid it when possible. If you fail
834+ to invalidate something, outdated caches will be served for a potentially
835+ long time. Instead, use short cache lifetimes or use the validation model,
836+ and adjust your controllers to perform efficient validation checks as
837+ explained in :ref: `optimizing-cache-validation `.
838+
839+ Furthermore, since invalidation is a topic specific to each type of reverse
840+ proxy, using this concept will tie you to a specific reverse proxy or need
841+ additional efforts to support different proxies.
842+
843+ Sometimes, however, you need that extra performance you can get when
844+ explicitly invalidating. For invalidation, your application needs to detect
845+ when content changes and tell the cache to remove the URLs which contain
846+ that data from its cache.
847+
848+ .. tip ::
849+
850+ If you want to use cache invalidation, have a look at the
851+ `FOSHttpCacheBundle `_. This bundle provides services to help with various
852+ cache invalidation concepts, and also documents the configuration for the
853+ a couple of common caching proxies.
854+
855+ If one content corresponds to one URL, the ``PURGE `` model works well.
856+ You send a request to the cache proxy with the HTTP method ``PURGE `` (using
857+ the word "PURGE" is a convention, technically this can be any string) instead
858+ of ``GET `` and make the cache proxy detect this and remove the data from the
859+ cache instead of going to Symfony to get a response.
860+
861+ Here is how you can configure the Symfony reverse proxy to support the
862+ ``PURGE `` HTTP method::
863+
864+ // app/AppCache.php
865+
866+ // ...
867+ use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
868+ use Symfony\Component\HttpFoundation\Request;
869+ use Symfony\Component\HttpFoundation\Response;
870+
871+ class AppCache extends HttpCache
872+ {
873+ protected function invalidate(Request $request, $catch = false)
874+ {
875+ if ('PURGE' !== $request->getMethod()) {
876+ return parent::invalidate($request, $catch);
877+ }
878+
879+ if ('127.0.0.1' !== $request->getClientIp()) {
880+ return new Response('Invalid HTTP method', Response::HTTP_BAD_REQUEST);
881+ }
882+
883+ $response = new Response();
884+ if ($this->getStore()->purge($request->getUri())) {
885+ $response->setStatusCode(200, 'Purged');
886+ } else {
887+ $response->setStatusCode(200, 'Not found');
888+ }
889+
890+ return $response;
891+ }
892+ }
893+
894+ .. caution ::
895+
896+ You must protect the ``PURGE `` HTTP method somehow to avoid random people
897+ purging your cached data.
898+
899+ **Purge ** instructs the cache to drop a resource in *all its variants *
900+ (according to the ``Vary `` header, see above). An alternative to purging is
901+ **refreshing ** a content. Refreshing means that the caching proxy is
902+ instructed to discard its local cache and fetch the content again. This way,
903+ the new content is already available in the cache. The drawback of refreshing
904+ is that variants are not invalidated.
905+
906+ In many applications, the same content bit is used on various pages with
907+ different URLs. More flexible concepts exist for those cases:
908+
909+ * **Banning ** invalidates responses matching regular expressions on the
910+ URL or other criteria;
911+ * **Cache tagging ** lets you add a tag for each content used in a response
912+ so that you can invalidate all URLs containing a certain content.
913+
914+ .. index ::
915+ single: Cache; ESI
916+ single: ESI
805917
806918.. _edge-side-includes :
807919
@@ -1048,70 +1160,6 @@ The ``render_esi`` helper supports two other useful options:
10481160 of ``continue `` indicating that, in the event of a failure, the gateway cache
10491161 will simply remove the ESI tag silently.
10501162
1051- .. index ::
1052- single: Cache; Invalidation
1053-
1054- .. _http-cache-invalidation :
1055-
1056- Cache Invalidation
1057- ------------------
1058-
1059- "There are only two hard things in Computer Science: cache invalidation
1060- and naming things." -- Phil Karlton
1061-
1062- You should never need to invalidate cached data because invalidation is already
1063- taken into account natively in the HTTP cache models. If you use validation,
1064- you never need to invalidate anything by definition; and if you use expiration
1065- and need to invalidate a resource, it means that you set the expires date
1066- too far away in the future.
1067-
1068- .. note ::
1069-
1070- Since invalidation is a topic specific to each type of reverse proxy,
1071- if you don't worry about invalidation, you can switch between reverse
1072- proxies without changing anything in your application code.
1073-
1074- Actually, all reverse proxies provide ways to purge cached data, but you
1075- should avoid them as much as possible. The most standard way is to purge the
1076- cache for a given URL by requesting it with the special ``PURGE `` HTTP method.
1077-
1078- Here is how you can configure the Symfony reverse proxy to support the
1079- ``PURGE `` HTTP method::
1080-
1081- // app/AppCache.php
1082-
1083- // ...
1084- use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
1085- use Symfony\Component\HttpFoundation\Request;
1086- use Symfony\Component\HttpFoundation\Response;
1087-
1088- class AppCache extends HttpCache
1089- {
1090- protected function invalidate(Request $request, $catch = false)
1091- {
1092- if ('PURGE' !== $request->getMethod()) {
1093- return parent::invalidate($request, $catch);
1094- }
1095-
1096- $response = new Response();
1097- if ($this->getStore()->purge($request->getUri())) {
1098- $response->setStatusCode(Response::HTTP_OK, 'Purged');
1099- } else {
1100- $response->setStatusCode(Response::HTTP_NOT_FOUND, 'Not purged');
1101- }
1102-
1103- return $response;
1104- }
1105- }
1106-
1107- .. versionadded :: 2.4
1108- Support for HTTP status code constants was introduced in Symfony 2.4.
1109-
1110- .. caution ::
1111-
1112- You must protect the ``PURGE `` HTTP method somehow to avoid random people
1113- purging your cached data.
1114-
11151163Summary
11161164-------
11171165
@@ -1139,3 +1187,4 @@ Learn more from the Cookbook
11391187.. _`P6 - Caching: Browser and intermediary caches` : http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache
11401188.. _`FrameworkExtraBundle documentation` : http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/cache.html
11411189.. _`ESI` : http://www.w3.org/TR/esi-lang
1190+ .. _`FOSHttpCacheBundle` : http://foshttpcachebundle.readthedocs.org/
0 commit comments