4

I have a module that in hook_preprocess() checks with drupal_get_http_header() whether Drupal is returning a 403 or 404 error, but in Drupal 8 that function is deprecated, since header handling is being shifted to a Symfony response object.

I am using code similar to the following one.

$header = drupal_get_http_header('Status');

switch ($header) {
  case '403 Forbidden':
    // Add new headers.
    // …
    break;

  case '404 Not Found':
    // Add new headers.
    // …
    break;
}

What code should I use in Drupal 8? If that means to use a different hook, that is fine.

I would also be interested in the case I need to add HTML output to the page. I guess that in this case I should use hook_page_alter(), but I still don't know how to access the response object for the page being served.

2

You can subscribe to the Symfony KernelEvents::RESPONSE event:

The RESPONSE event occurs once a response was created for replying to a request

This event allows you to modify or replace the response that will be replied. The event listener method receives a Symfony\Component\HttpKernel\Event\FilterResponseEvent instance.

To do so, create a new module ("response_test" in this example), with the usual .info.yml and .module file.

Then register your event subscriber in the module's services file:

response_test.services.yml

services:
    response_test.response_subscriber:
      class: Drupal\response_test\ResponseSubscriber
      tags:
        - { name: event_subscriber }

Now all you need is the class to handle the event:

lib/Drupal/response_test/ResponseSubscriber.php

<?php 

namespace Drupal\response_test;

use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ResponseSubscriber implements EventSubscriberInterface {

  public function onRespond(FilterResponseEvent $event) {
    if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) {
      return;
    }

    $response = $event->getResponse();
    if ($response->getStatusCode() == 404) {
      // Prepare a new Symfony\Component\HttpFoundation\Response and use
      $event->setResponse($new_response);

      // or call one of the setter methods on $response, the changes will persist
    }
  }

  public static function getSubscribedEvents() {
    $events[KernelEvents::RESPONSE][] = array('onRespond');
    return $events;
  }

}

I'm a little unsure about changing the HTML content in this context; you have access to $response->getContent() and $response->setContent() so you can manipulate the raw string directly, but as far as I can tell everything's already rendered at this point.

1

To check for error codes you can use the following snippet. It won't work for 200 status codes though. Since there's no exception.

use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

$exception = \Drupal::requestStack()->getCurrentRequest()->attributes->get('exception');
if ($exception instanceof HttpExceptionInterface) {
  $status_code = $exception->getStatusCode();
  // ...
}

I'm unsure if it's safe to assume that the status code must be 200 if there's no exception in the first place. If yes you could use the following snippet to cover a 200er response.

if (!\Drupal::requestStack()->getCurrentRequest()->attributes->has('exception')) {
  $status_code = '200';
}
  • The request attribute exception is only present in a subrequest, which Drupal uses to build a themed 403/404 response with configurable content. The standard exception handling, which takes place in the main request, does not use this attribute. The status code is accessible in the exception thrown and once handled by KernelEvents::EXCEPTION in the response. Which don't necessarily contain the same status code, the exception subscriber can put in the response what it wants. – 4k4 12 hours ago
  • See for example drupal.stackexchange.com/questions/231195/… – 4k4 12 hours ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.