Full Page Cacheable Requests in Magento 2 – Determining Factors

cachefull-page-cachemagento2PHP

Magento 2 comes stock with a full page caching feature. However, it's not clear how the framework determines which URL end-points need to be cached. For example, if I create a simple controller that acts as a JSON endpoint

$data = ...;
$result = $this->resultJsonFactory->create();       
return $result->setData($data);

The system seems smart enough to know not to cache this.

curl -I 'http://magento2.example.com/my/custom/endpoint'
//...
X-Magento-Cache-Debug: MISS

I've been able to track the built in caching functionality to this method (used by the built-in plugin)

#File: lib/internal/Magento/Framework/App/PageCache/Kernel.php
public function process(\Magento\Framework\App\Response\Http $response)
{
    if (preg_match('/public.*s-maxage=(\d+)/', $response->getHeader('Cache-Control')->getFieldValue(), $matches)) {
        $maxAge = $matches[1];
        $response->setNoCacheHeaders();
        if ($response->getHttpResponseCode() == 200 && ($this->request->isGet() || $this->request->isHead())) {
            $tagsHeader = $response->getHeader('X-Magento-Tags');
            $tags = $tagsHeader ? explode(',', $tagsHeader->getFieldValue()) : [];

            $response->clearHeader('Set-Cookie');
            $response->clearHeader('X-Magento-Tags');
            if (!headers_sent()) {
                header_remove('Set-Cookie');
            }
            $this->cache->save(serialize($response), $this->identifier->getValue(), $tags, $maxAge);
        }
    }
}

Which seems to examine the response object, and only cache requests if they're a HTTP 200, either a GET or HEAD request. It also uses the Max-Age Cache-Control header to ensure values are saved in the cache for an appropriate amount of time.

So, it's clear from this code that something instructs the system (i.e. sets cache headers on the response) to cache the request. What's not clear is where this happens during Magento's request flow, and which requests gets full page caching and which do not.

Best Answer

Response is marked as cacheable in \Magento\PageCache\Model\Layout\LayoutPlugin::afterGenerateXml only in case if there are no blocks in the layout of current page marked with cacheable="false" attribute, like this:

<block class="Magento\Checkout\Block\Registration" name="checkout.registration" template="registration.phtml" cacheable="false"/>

By default all CMS, product and category pages should be cacheable, their layouts were refactored so as not to contain non-cacheable blocks.

Also keep in mind, there is a bug related to usage of cacheable="false" on product pages described here.

Related Topic