With Symfony2 why are ESI tags inside cached responses ignored?

旧街凉风 提交于 2019-12-06 10:21:33

问题


I have an ecommerce application that I'm try to set up for caching - initially via the Symfony2 Reverse Proxy, but then ultimately via Varnish in production. I'm using Symfony 2.1.8 on Apache2.

My problem is I cannot get the ESI tags to be re-checked for each request when the primary controller action is cached (important for private content like the basket contents), but I don't understand why.

For example, I cache the homepage with the following code:

public function indexAction(Request $request)
{
    // check cache
    $homepage = $this->getHomepage();

    $response = new Response();
    $response->setPublic();
    $etag = md5('homepage'.$homepage->getUpdated()->getTimestamp());
    $response->setETag($etag);
    $response->setLastModified($homepage->getUpdated());

    if ($response->isNotModified($request))
    {
        // use cached version
        return $response;
    }
    else
    {
        return $this->render(
            'StoreBundle:Store:index.html.twig',
            array(
                'page' => $homepage
            ),
            $response
        );
    }
}

The rendered template extends the base layout template which includes the following ESI to show the basket:

{% render 'PurchaseBundle:Basket:summary' with {}, { 'standalone': true } %}

(Edit: After reading Diego's answer, I have also used the recommended syntax:

{% render url('basket_summary') with {}, {'standalone': true} %}

Unfortunately this had not made any difference.)

I've been playing with the code for the basket summary quite a bit, but this is what I have at present.

public function summaryAction()
{
    $response = new Response();
    $response->setPrivate();
    $response->setVary(array('Accept-Encoding', 'Cookie'));

    if ($this->basket->getId())
    {
        $etag = md5($this->getUniqueEtag());
        $response->setLastModified($this->basket->getUpdated());
    }
    else
    {
        $etag = md5('basket_summary_empty');
    }

    $response->setETag($etag);

    if ($response->isNotModified($this->request))
    {
        // use cached version
        return $response;
    }
    else
    {
        return $this->render(
            'PurchaseBundle:Basket:summary.html.twig',
            array(
                'basket' => $this->basket
            ),
            $response
        );
    }
}

On pages other than the homepage (which are not cached yet) the basket summary caching works just fine, it always displays the correct data. It's only when you return to the homepage that you'd see outdated information. Logging confirms that summaryAction is not called on the homepage unless indexAction actually renders.

Edit

Using error_log($kernel->getLog()) after each page request I get this for a non-cached page:

GET /categories/collections: miss; GET /_internal/secure/PurchaseBundle:Basket:summary/none.html: stale, valid, store; GET /_internal/secure/CatalogBundle:Search:form/none.html: miss; GET /esi/menu/main: fresh

And this for the cached homepage:

GET /: fresh

I must be missing something obvious, but the documentation doesn't appear to cover this, yet it implies it's just the sort of thing ESI is supposed to be used for.


回答1:


It appears that ESI in Symfony2 doesnt work with the Latmodified/Etag cache validation structure that you used. See here: https://groups.google.com/forum/?fromgroups=#!topic/symfony2/V4BItzpLbOs

Similar question here: Edge Side Includes and validation cache in Symfony 2

I've been trying to do the same as you, but can only get ESI to work by using expiration cache.




回答2:


Since 2.0.20/2.1.5 Symfony2 takes a fully qualified URL instead of a controller logical path, as per CVE-2012-6431. So, instead of your current ESI:

{% render 'PurchaseBundle:Basket:summary' with {}, { 'standalone': true } %}

You should create a route and then use the url method on twig:

{% render url('basket_summary') with {}, {'standalone': true} %}

Also note that today (March 1st) a new stable version of Symfony (2.2.0) has been released with major improvements on sub-requests management. With this new version, you can take two approaches (extracted from the master version of the HTTP Cache chapter in The Book):

{# you can use a controller reference #}
{{ render_esi(controller('...:news', { 'max': 5 })) }}

{# ... or a URL #}
{{ render_esi(url('latest_news', { 'max': 5 })) }}

The side notes on the current version of the linked chapter are worth reading as well, as they contain delicious pieces of information and nice tips that may help you finding the actual problem.



来源:https://stackoverflow.com/questions/15163121/with-symfony2-why-are-esi-tags-inside-cached-responses-ignored

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!