Caching
Page cache
A JSON page is cached like an HTML page: the encoded response is stored in
the pages cache with the lifetime derived from the page properties and
config., and it is invalidated by the same operations (saving
records on the page, "Flush frontend caches", cache:). No
headless-specific cache exists.
Uncached fields
Fields rendered by a USER_ cObject — Extbase plugins with non-cacheable
actions, EXT:, EXT: — are not part of the cached page. TYPO3
stores an <!-- placeholder and fills it on every request.
Inside a JSON document that placeholder would sit in a string, so the JSON
cObject wraps it in HEADLESS_ markers
(HEADLESS_ with if, nested variants for
JSON objects rendered inside USER_ output). After TYPO3 has rendered
the uncached parts, the headless/ middleware
replaces each marker with the JSON-encoded value: a string, null, or the
object itself when the plugin already returned JSON.
The middleware runs only when headless mode applies to the request. Markers
that show up verbatim in the output mean the site loads the headless
TypoScript but runs with headless: 0.
A page with a USER_ field is still stored in the page cache; only that
field is computed per request. The seo object is rebuilt on those requests
too, because page title and meta tags may depend on the uncached plugin. Such
a page gets no client cache headers, see below.
HTTP caching
lib. sends Content- on
every response and sets config.. Cacheable pages
requested without a logged-in frontend or backend user are sent with
Expires, ETag, Cache- and Pragma: public,
so browsers, reverse proxies and CDNs may cache them for the page cache
lifetime. No Last- header is sent. The core option
config. switches to
Cache-, so only shared caches keep
the page: force always, auto only when the request comes through a
configured reverse proxy (SYS/).
On a headless: 2 site one URL returns HTML or JSON depending on the
Accept header, so a shared cache has to key on that header. Headless does
not send Vary: Accept itself; add it in the site package, where it applies
to the JSON and the HTML page alike:
page.config.additionalHeaders.40.header = Vary: Accept
Every other response — logged-in users, workspace previews, and pages with
USER_ fields — gets Cache-; only the server
page cache applies to them.
Per-field caching
An expensive field inside a JSON object can cache its own result with the
core cObject property cache, independent of the page cache. The cache is
checked before the field is rendered, so for a JSON field a hit skips the
data processors; the cached value is the encoded JSON fragment. On any
other cObject, e.g. TEXT with data, the processors run after
the cObject has been rendered and are not covered by its cache — make the
field a JSON object to cache them. Do not use std
for this: the std of a JSON object runs only after the processors
and the encoding, so it saves no work.
page.10.fields.related = JSON
page.10.fields.related {
dataProcessing.10 = headless-database-query
dataProcessing.10 {
table = tx_myext_domain_model_item
pidInList = 42
as = items
fields {
title = TEXT
title.field = title
}
}
cache {
key = related-items-{page:uid}-{siteLanguage:languageId}
key.insertData = 1
lifetime = 3600
}
}
Include everything the output depends on in the key — at least the language, as above.
Do not cache fields that contain USER_ output this way: the markers
would be stored instead of the rendered value.