The Render API bubbles up cacheability metadata all the way to the
Response object (usually a
HtmlResponse) that implement this interface.
But really, any response can have this cacheability metadata. For example,
CacheableJsonResponse allows you to associate cacheability metadata with a JSON response: if the data in the JSON response originates from data/objects with cacheability metadata, then we know perfectly what the JSON response varies by (the cache contexts), what it is invalidated by (the cache tags) and how long it can be cached (its max-age). Similarly,
CacheableRedirectResponse can be used for example for entities that have URL aliases, which never change, except when the entity's cache tag is invalidated.
Consequently, it is the cacheability metadata on these response objects that allow Page Cache and Dynamic Page Cache to cache responses, while always guaranteeing the response is up-to-date (thanks to cache tags) and that the right variation is sent in case of Dynamic Page Cache (thanks to cache contexts).
You can debug cacheable responses (responses that implement this interface, which may be cached by Page Cache or Dynamic Page Cache) by setting the
http.response.debug_cacheability_headers container parameter to
true, in your
services.yml. Followed by a container rebuild, which is necessary when changing a container parameter.
That will cause Drupal to send