Developers
Responses
Everything a hub sends back is attached to one object. The Response
facade resolves Hubzero\Http\Response,
which extends Symfony's Response and adds output compression and a
chainable header(). The application creates it during boot, the template
fills its content, and the application sends it — so in the ordinary case
you never touch it.
When you actually need it
Four cases, and outside them you should not be touching the response:
- An AJAX task that returns JSON instead of a page.
- A feed or export — CSV, iCalendar, an XML dump — where you set the content type and write the body yourself.
- A system plugin rewriting the finished page on
onAfterRender. - Middleware that must send something before the application would.
Serving a file off disk is not one of them. Use
Hubzero\Content\Server, which handles
disposition, length and byte ranges.
Getting at it
use Response;
Response::header('Content-Type', 'application/json');
or, equivalently, from the container:
$response = App::get('response');
$response->header('Content-Type', 'application/json');
Headers
header($key, $values, $replace = true) sets a header and returns the
response, so several can be chained:
$response = App::get('response');
$response->header('Content-Type', 'application/json')
->header('X-Total-Count', $total)
->header('Cache-Control', 'no-store');
The most common use by far is switching the content type for an AJAX task, then echoing the payload and ending the request:
public function statusTask()
{
Response::header('Content-Type', 'application/json');
echo json_encode(array('state' => $booking->get('state')));
App::close();
}
App::close() calls exit(). Nothing after it runs, and nothing else gets
appended to the body.
Content
setContent($output) replaces the body; it takes a string. getContent()
reads it back. The site template's output is set here at the end of the
render stage, so a system plugin listening on onAfterRender can read the
finished page, alter it, and set it back:
public function onAfterRender()
{
$body = App::get('response')->getContent();
App::get('response')->setContent(str_replace($from, $to, $body));
}
Compression and sending
compress($value) marks the response for gzip. The application turns it on
from the gzip global configuration option; when set, send() checks the
browser's Accept-Encoding, confirms zlib is loaded and that headers have
not gone out, and compresses the body on the way past. It is a no-op
otherwise, so nothing breaks on a server without zlib.
send($flush = false) writes the headers and then the body. With $flush
true it also closes the connection — fastcgi_finish_request() where that
exists — so slow work can carry on after the browser has the page. The
application calls this once, at the end of the request; a component calling
it is almost always a mistake.
Serving a file off disk is a separate path with its own headers and byte
ranges. Use Hubzero\Content\Server, not the
response object.
Redirects
A redirect is a response too, of a different class.
Hubzero\Http\RedirectResponse
extends Symfony's, and its send() resolves the target first: an
index.php-relative URL is prefixed with Request::base(), line breaks
are stripped, and a URL with no scheme is made absolute against the current
scheme, host and path. That is why a component can redirect to a route
result without worrying whether it came back absolute.
App::redirect() builds one, attaches the request, optionally queues a
message, sends it, and exits:
App::redirect(
Route::url('index.php?option=com_support'),
Lang::txt('COM_SUPPORT_TICKET_SAVED'),
'success'
);
See redirect for the details, including the message types and what happens to the code after the call.
Status codes and errors
Do not set an error status on the response by hand. App::abort($code, $message) throws the exception the error handler is looking for, and the
error template renders the right page:
| Code | Exception thrown |
|---|---|
| 403 | Hubzero\Error\Exception\NotAuthorizedException |
| 404 | Hubzero\Error\Exception\NotFoundException |
| 405 | Hubzero\Error\Exception\MethodNotAllowedException |
| anything else | Hubzero\Error\Exception\RuntimeException with that code |
if (!$row->get('id'))
{
App::abort(404, Lang::txt('COM_BLOG_ERROR_ENTRY_NOT_FOUND'));
}
Throwing one of those exceptions yourself has the same effect;
App::abort() is the shorter way to say it.
Rewritten and checked against 2.4-main @ 348f0057c2 on 2026-09-10.