Search code examples
cachingsymfonyreverse-proxyesi

Symfony2: Private ESI Fragment


I am wondering if there exists something like a private ESI fragment. In the docs I read :

  1. "set the shared max age - which also marks the response as public"
  2. "Once you start using ESI, remember to always use the s-maxage directive instead of max-age. As the browser only ever receives the aggregated resource, it is not aware of the sub-components, and so it will obey the max-age directive and cache the entire page. And you don't want that."

I don't fully understand if I am or am not able to cache certain parts of my page on a per-user basis. Could someone please explain?

Thanks in advance!


Solution

  • You can cache parts of the page on a per user basis.

    They key is the varnish config, you set shared max age as normal for your ttl, and that esi request will then be cached for that user.

    Then have a look at this Varnish cookbook caching for logged in users the key is that you need a unique cookie with a hashed userid and replace myapp_unique_user_id in the example with your cookie name.

    This is an example controller which has both the cached and non-cached action in it.

    <?php
    
    namespace MyTest\Bundle\HomepageBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
    use Symfony\Component\HttpFoundation\Response;
    
    class TestController extends Controller
    {
        /**
         * UnCached html content
         *
         * @Route("/test_cache", name="homepage")
         *
         * @return \Symfony\Component\HttpFoundation\Response
         */
        public function homepageAction()
        {
            return $this->render('MyTestHomepageBundle::index.html.twig');
        }
    
        /**
         * Cached user specific content
         *
         * @param integer $myTestUserId
         *
         * @return \Symfony\Component\HttpFoundation\Response
         *
         * @Route("/test_user_cached/{myTestUserId}", name="homepage_user_specific_content")
         */
        public function userSpecificContentAction($myTestUserId)
        {
            $response = $this->render('MyTestHomepageBundle::userSpecificContent.html.twig', array('userId' => $myTestUserId));
            $response->setPublic();
            $response->setSharedMaxAge(3600);
    
            return $response;
        }
    }
    

    This is your index.html

    <!DOCTYPE html>
    <head></head>
    <body>
    
    <h1>My Test homepage - {{ "now"|date("F jS \\a\\t g:i:s") }}</h1>
    {{ render_esi(url('homepage_user_specific_content')) }}
    </body>
    

    and userSpecificContent.html.twig

    UserId: {{ userId }}  - {{ "now"|date("F jS \\a\\t g:i:s") }}