Skip to content

Forcing browser caching on custom controller

I have a custom controller with this code:

use MagentoFrameworkAppActionHttpGetActionInterface;
use MagentoFrameworkAppResponseHttpFactory;
use MagentoFrameworkAppResponseInterface;
use MagentoFrameworkControllerResultInterface;
use MagentoFrameworkExceptionNotFoundException;
use MagentoFrameworkViewElementTemplate;
use MagentoFrameworkViewResultPageFactory;

class Entries implements HttpGetActionInterface
{
    public function __construct(
        private Navigation           $navigation,
        private readonly PageFactory $resultPageFactory,
        private readonly HttpFactory $httpResponseFactory
    )
    {
    }

    /**
     * Execute action based on request and return result
     *
     * @return ResultInterface|ResponseInterface
     * @throws NotFoundException
     */
    public function execute()
    {
        $resultPage = $this->resultPageFactory->create();

        $categories = $this->navigation->getNavigation(5);

        $content = $resultPage->getLayout()
            ->createBlock(Template::class)
            ->setTemplate('Magento_Theme::html/header/topmenu/menu.phtml')
[...]
            ->toHtml();

        $response = $this->httpResponseFactory->create();
        $response->setContent($content);
        $response->setPublicHeaders(3600);
        return $response;
    }
}

setPublicHeader should set a max-age and force browser caching.

        $this->setHeader('pragma', 'cache', true);
        $this->setHeader('cache-control', 'public, max-age=' . $ttl . ', s-maxage=' . $ttl, true);
        $this->setHeader('expires', $this->getExpirationHeader('+' . $ttl . ' seconds'), true);

But it doesn’t.

$ http -ph https://example.local/theme/menu/entries
HTTP/1.1 200 OK
Cache-Control: max-age=0, must-revalidate, no-cache, no-store

Is this expected behavior, when the full page cache is on? I tried to debug and in Magento the headers seem to be overwritten, but did not fully understand what’s happening here with the full page cache.