Symfony 3.4的HTTP缓存,始终使用Cache-Control:max-age = 0,must-revalidate,private。

11

我尝试在注释中

 * @Cache(expires="+10 hours", public=false) 

或者在控制器中

$maxAge = 60*60;
$response->setExpires(Carbon::create()->addHour());
$response->setSharedMaxAge($maxAge);
$response->setPublic();
$response->setMaxAge($maxAge);

仍然具有Cache-Control: max-age=0, must-revalidate, private

应用程序使用会话,用户已登录 - 我想要缓存私有,但没有成功 - 我总是得到这个。

我添加了FOS\HttpCacheBundle\FOSHttpCacheBundle()

(只是添加) 希望它覆盖Symfony缓存并允许发送缓存私有 - 但没有任何改变。

4个回答

21

从Symfony 3.4和4.0开始,此行为是新的。如果已初始化用户会话,则始终会设置如问题中所述的标头。

自Symfony 4.1引入后,您可以覆盖此行为。但是,由于这是一个新功能,因此不会向Symfony 3.4回溯兼容。

$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');

您可以在Symfony文档中了解更多信息:HTTP缓存和用户会话


3
我是不是理解错了,或者这意味着在v3.4中,只要您有一个活动用户会话,就无法使用HTTP缓存与ESI? - userfuser
显然,您正在正确阅读。对于基于ESI的设置来说,这是一个非常重要的B/C中断,即使存在会话cookie(无论实际登录状态如何),也不能缓存与用户无关的响应。错误报告:https://github.com/symfony/symfony/issues/29151 - MicE

4

可能最好的方法是使用服务装饰器,但目前我更喜欢采用不太正规的方式。

在我的情况下,我只需要为特定控制器提供共享缓存头。

Symfony 3.4.*的解决方法:

services.yml中创建一个优先级低于Symfony\Component\HttpKernel\EventListener\SessionListener的监听器(不知道这是否被推荐):

AppBundle\Listener\ResponseListener:
    tags:
        - { name: kernel.event_listener, event: kernel.response, priority: -1001 }

然后在AppBundle\Listener\ResponseListener中:

<?php

namespace AppBundle\Listener;

use Symfony\Component\HttpKernel\Event\FilterResponseEvent;

class ResponseListener
{
    public function onKernelResponse(FilterResponseEvent $event)
    {
        $response = $event->getResponse();

        $controller = $event->getRequest()->attributes->get('_controller');
        $requiredAssetAction = "AppBundle\Controller\Website\AssetsController::assetAction";

        if ($controller == $requiredAssetAction) {
            $response->headers->addCacheControlDirective('max-age', 900);
            $response->headers->addCacheControlDirective('s-maxage', 900);
            $response->headers->addCacheControlDirective('must-revalidate', true);
            $response->headers->addCacheControlDirective('public', true);
            $response->headers->removeCacheControlDirective('private');

        }

        $event->setResponse($response);
    }

}

1
非常好的答案!您可以使用 if (strpos($controller, 'AssetController') !== false) 将更改应用于整个控制器。 - Roubi

0

我在一个遗留的3.4应用程序中解决了这个问题,只需实现来自symfony/http-kernel组件的AbstractSessionListenerSessionListener类中的逻辑,并在我的监听器中覆盖服务并将其别名为我的实现:

  session_listener:
    alias: 'Vendored\Symfony\EventSubscriber\SessionListener'
    tags:
      - { name: 'kernel.event_subscriber' }

0

你是否使用了像Symfony这样的反向代理?https://symfony.com/doc/3.4/http_cache.html#symfony-reverse-proxy

此外,在你的示例中,注释的public=false,而控制器将具有public true。

另一个可能的问题是你的Web服务器(如Apache等)已配置添加该标头,或者在你的.htaccess文件中指定了此选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接