How to: add a custom page-type handler, that manipulates the response headers

Hi! My use-case: I have many page-type handlers to deal with ajax-stuff, config-loading, and so on. Until V12 it was possible to use this simple pattern:

custom = PAGE
custom {
    typeNum = 213123
    10 = USER
    10.userFunc = some_callable
}

And in the callable i had the possibility to add HTTP Headers via the TSFE object by manipulating the config array. But this will be impossible very soon. In V13 this is deprecated and in V14 it will be gone i fear.

I know, i can add a middleware, but i already added a lot of middlewares and in my opinion it is not a good pattern, to use a middleware for everything. It feels clumsy and requires more boilerplate.

I already opened a feature request for this a few years ago - i suggested, that you can add a psr request handler as static route. This would be much nicer IMO.

See here: Making sure you're not a bot!
But that got closed without a real solution.

routes:
  simpleExample:
    route: simple
    type: PHPRequestHandler
    requestHandler: Vendor\Package\Controller\SomeController->dispatch

An alternative could be a “psr-handler” for page-types.

custom = PAGE
custom {
    typeNum = 213123
    requestHandler = some_callable
}

Will a psr middleware really be the only way to programmatically handle a psr request object in the future?

A page type gives additional advantages like using the default caching mechanism. And there are situations where i need to add variable headers - i cant do this in the static page.config.additionalHeaders configuration.

I think the practical answer in v13/v14 is yes, the response should be finalized outside the old PAGE/userFunc pattern.

If you need dynamic headers, I would move only the header logic into a PSR-15 middleware and keep the page-type route as the signal. In other words:

  • let `typeNum` or route attributes identify the endpoint
  • generate the content in your controller / page-type logic as before
  • add or override headers in a middleware late in the stack, only when that request matches your custom type

That keeps the middleware pretty small, and you still get TYPO3’s normal response handling instead of mutating TSFE internals that are being removed.

If caching is the main reason to stay with PAGE, another option is to return a proper PSR-7 response from the endpoint and set the headers there, but I would not expect TYPO3 to bring back TSFE-style header mutation for page types.

So, not a very satisfying answer, but I would treat middleware / PSR response handling as the forward-compatible path now.