3

我有一个电子商务应用程序,我正在尝试设置缓存 - 最初通过 Symfony2 反向代理,但最终通过生产中的 Varnish。我在 Apache2 上使用 Symfony 2.1.8。

我的问题是当主控制器操作被缓存时,我无法为每个请求重新检查 ESI 标签(对于像购物篮内容这样的私有内容很重要),但我不明白为什么。

例如,我使用以下代码缓存主页:

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

呈现的模板扩展了基本布局模板,其中包括以下 ESI 以显示篮子:

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

(编辑:阅读 Diego 的回答后,我也使用了推荐的语法:

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

不幸的是,这没有任何区别。)

我一直在使用篮子摘要的代码,但这是我目前所拥有的。

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

在主页以外的页面(尚未缓存)上,购物篮摘要缓存工作得很好,它始终显示正确的数据。只有当您返回主页时,您才会看到过时的信息。日志记录确认summaryAction除非indexAction实际呈现,否则不会在主页上调用。

编辑

在每个页面请求之后使用error_log($kernel->getLog())我得到这个非缓存页面:

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

这对于缓存的主页:

GET /: fresh

我一定遗漏了一些明显的东西,但文档似乎没有涵盖这一点,但这意味着它只是 ESI 应该用于的那种事情。

4

2 回答 2

3

根据CVE-2012-6431,从 2.0.20/2.1.5 开始,Symfony2 采用完全限定 URL 而不是控制器逻辑路径。因此,而不是您当前的 ESI:

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

您应该创建一个路由,然后在 twig 上使用 url 方法:

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

另请注意,今天(3 月 1 日)新的 Symfony 稳定版本(2.2.0)已经发布,对子请求管理进行了重大改进。使用这个新版本,您可以采用两种方法(摘自本书中 HTTP 缓存章节的主版本):

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

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

当前版本的链接章节的附注也值得一读,因为它们包含有用的信息和很好的提示,可以帮助您找到实际问题。

于 2013-03-01T17:31:09.850 回答
2

Symfony2 中的 ESI 似乎不适用于您使用的 Latmodified/Etag 缓存验证结构。见这里:https ://groups.google.com/forum/?fromgroups=#!topic/symfony2/V4BItzpLbOs

类似问题: Edge Side Includes and validation cache in Symfony 2

我一直在尝试和你做同样的事情,但只能通过使用过期缓存来让 ESI 工作。

于 2013-04-11T02:09:39.010 回答