ESI缓存在特定路由上

时间:2016-07-27 15:04:50

标签: symfony varnish esi

如何让varnish将动态菜单缓存到不同的状态?

我当前的项目(基于Symfony 2.8)使用KnpMenuBundle和varnish来缓存页面。它还使用ESI来禁用某些页面上的一个特定元素的缓存。其中包括菜单。但由于这不是一个变化很大的元素,我想知道是否可以缓存菜单的不同状态并将相关状态传递给当前调用菜单的页面。

涉及的主要文件如下:

main.html.twig

{{ render_esi(controller('AppBundle:Menu:mainESI')) }}

的appbundle \控制器\ MenuController.php

    public function mainESIAction($path = null)
    {
        return $this->render('menu/main_menu_esi.html.twig', [
            'path' => $path
        ]);
    }

菜单/ main_menu_esi.html.twig

    {{ knp_menu_render('main-menu', {'template':'menu/main_menu.html.twig'}) }}

3 个答案:

答案 0 :(得分:2)

我对Symfony知之甚少,但总的来说,如果你能从cookies中获得所需的状态,你可以试试这个场景:

在recv()中

  • 解析Cookie标头并将您的状态提取到自定义请求HTTP标头,让我们说“X-Menu-Mode:admin”
  • 删除所有Cookie

in hash():

  • 将该标题添加到哈希(默认情况下有URL和主机AFAIK)

在miss / pass(3.x)或backend_fetch(4.x)中:

  • 从X-Menu-Mode
  • 重建bereq中的Cookie标头
  • 从bereq
  • 删除X-Menu-Mode

我使用这个场景非常成功。 ESI包含的片段现在可完全缓存,并为每个唯一的cookie值提供不同的版本。

答案 1 :(得分:1)

你不能。

对于Varnish,url将是相同的,因此它将呈现相同的。

在外面应用您的逻辑并在路线中添加参数:

{% if is_granted('ROLE_ADMIN') %}
    {% set menu_mode = 'admin' %}
{% else %}
    {% set menu_mode = 'normal' %}
{% endif %}

{{ render_ssi(controller('AppBundle:Menu:mainESI',{'menu_mode':menu_mode}))  }}

答案 2 :(得分:1)

毕竟这是可能的。我需要的解决方案如下:

  1. 将当前路径传递给树枝:
  2. 的appbundle /资源/视图/ base.html.twig

    {{ render_esi(controller('AppBundle:Menu:mainESI', { 'currentPath': currentPath })) }}
    
    1. 获取te控制器操作中的变量:
    2. 的appbundle /控制器/ MenuAdminController.php

      public function mainESIAction($currentPath = null) 
      {
          return $this->render('menu/main_menu_esi.html.twig', [
               'currentPath' => $currentPath,
          ]);
      }
      
      1. 使用Matcher / Voter类:
      2. 的appbundle /匹配器/选民/ PathVoter.php

        <?php
        
        namespace AppBundle\Matcher\Voter;
        
        use Knp\Menu\ItemInterface;
        use Knp\Menu\Matcher\Voter\VoterInterface;
        use Symfony\Component\HttpFoundation\RequestStack;
        
        /**
         * Class PathVoter
         */
        class PathVoter implements VoterInterface
        {
            protected $uri;
        
            /**
             * @param RequestStack $requestStack
             */
            public function setRequest(RequestStack $requestStack)
            {
                if (($request = $requestStack->getCurrentRequest())) {
                    $pathInfo = $request->getPathInfo();
                    $requestUri = $request->getRequestUri();
        
                    if (!empty($pathInfo) && '/_fragment' === $pathInfo && !empty($request->attributes->get('currentPath'))) {
                        $this->uri = $request->attributes->get('currentPath');
                    } else {
                        $this->uri = $pathInfo;
                    }
                }
            }
        
            /**
             * @param ItemInterface $item
             * @return bool|void
             */
            public function matchItem(ItemInterface $item)
            {
                $uri = $item->getUri();
        
                if ((null === $this->uri) || (null === $uri)) {
                    return;
                }
        
                if ($item->getUri() === $this->uri) {
                    return true;
                }
        
                return;
            }
        }
        
        1. 注册投票人
        2. 的appbundle /资源/配置/ services.yml

          parameters:
              app.menu.voter.class: AppBundle\MenuBundle\Matcher\Voter\PathVoter
          
          services:
              app.menu.voter:
              class: %app.menu.voter.class%
              calls:
                  - [setRequest, [@request_stack]]
              tags:
                  - { name: knp_menu.voter }