Вопрос

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!

Это было полезно?

Решение

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") }}

Другие советы

As long as your ESI fragment response headers indicate it is not cacheable, varnish won't cache it. This is a typical use case -- caching the parent page with esi directives and not caching the contained esi includes. Those docs are telling you on the parent page which contains the ESI, use s-maxage so that the browser doesn't consider the page cacheable, only varnish. You should also, in my experience, remove the etag and last modified headers from a response that contains esi tags, as they won't respond to changes within the contents of the esi included fragments.

If you don't want to do this on the backend, you can do this in vcl_fetch (not linted):

if (beresp.ttl > 0 && beresp.do_esi) {
   set beresp.http.Cache-Control = "s-maxage=" beresp.ttl; 
   unset beresp.http.etag;
   unset beresp.http.last-modified;
   /* Optionally */
   unset beresp.http.expires;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top