logo

Extra Block Types (EBT) - Neue Erfahrung im Layout Builder❗

Extra Block Types (EBT) - gestylte, anpassbare Blocktypen: Diashows, Registerkarten, Karten, Akkordeons und viele andere. Eingebaute Einstellungen für Hintergrund, DOM Box, Javascript Plugins. Erleben Sie die Zukunft der Layouterstellung schon heute.

Demo EBT-Module EBT-Module herunterladen

❗Extra Absatztypen (EPT) - Erfahrung mit neuen Absätzen

Extra Paragraph Types (EPT) - analoger, auf Absätzen basierender Satz von Modulen.

Demo EPT-Module EPT-Module herunterladen

Scroll

Hinzufügen einer 500-Fehlerseite in Drupal mit Event Subscriber

11/06/2025, by Ivan

Menu

Oft stoßen wir auf eine 500-Fehlerseite, wenn Drupal, Dienste oder andere Websites nicht verfügbar sind. Wenn wir eine 500- (oder 501–504-) Fehlerseite sehen. In Drupal verwenden wir Exceptions, um zu prüfen, ob kritischer Code ausgeführt wurde. Wenn wir einen Fehler bekommen, zum Beispiel bei einer HTTP-Anfrage an eine andere Website, zeigt Drupal diesen Fehler an: „Die Website hat einen unerwarteten Fehler festgestellt. Bitte versuchen Sie es später noch einmal“:

Drupal Standard 500 Fehlerseite
Drupal Standard 500 Fehlerseite

Es ist nicht gut, ein WSOD (White Screen of Death) auf Ihrer Seite zu haben, daher verbessern wir dies und zeigen stattdessen eine gestaltete HTML-Seite an.

Ich habe eine gestaltete 500.html-Seite im Root-Verzeichnis meiner Website, aus Performance-Gründen. Wir können eine gestaltete Drupal-Seite für den 500-Fehler verwenden, aber ich werde dieselbe Seite auch für 503/504-Fehler in Apache/Nginx wiederverwenden und es ist einfacher, diese Seite als einzelne HTML-Datei an einem Ort zu haben.

500 HTML Seite
500 HTML Fehlerseite

Jetzt müssen wir Code in unser benutzerdefiniertes Modul DrupalBook Custom (drupalbook_custom) einfügen. In drupalbook_custom.services.yml müssen wir einen Event Subscriber hinzufügen:

services:
  drupalbook_custom.exception_subscriber:
    class: Drupal\drupalbook_custom\EventSubscriber\SeoExceptionSubscriber
    arguments: ['@config.factory']
    tags:
      - { name: event_subscriber, priority: -250 }

Hier ist der Code für drupalbook_custom/src/EventSubscriber/SeoExceptionSubscriber:

<?php

namespace Drupal\drupalbook_custom\EventSubscriber;

use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Utility\Error;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Ersetzt Drupal\Core\EventSubscriber\FinalExceptionSubscriber 500 Fehler.
 */
class SeoExceptionSubscriber implements EventSubscriberInterface {

  use StringTranslationTrait;

  /**
   * Konfigurationseinstellungen.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected ConfigFactoryInterface $configFactory;

  public function __construct(ConfigFactoryInterface $config_factory) {
    $this->configFactory = $config_factory;
  }

  /**
   * Behandelt alle nicht abgefangenen Exceptions und gibt eine eigene HTML-Antwort zurück.
   */
  public function onException(ExceptionEvent $event): void {
    // Zeige den normalen Drupal Stack Trace, wenn die Seite im VERBOSE-Modus ist.
    if ($this->isErrorLevelVerbose()) {
      return;
    }

    $exception = $event->getThrowable();

    // Basisnachricht (bei Bedarf für den Verbose-Modus erweitern).
    $error = Error::decodeException($exception);
    $message = new FormattableMarkup('@message', [
      '@message' => $error['!message'] ?? $this->t('Die Website hat einen unerwarteten Fehler festgestellt.'),
    ]);

    $html = $this->buildHtml((string) $message);
    $status = $exception instanceof HttpExceptionInterface
      ? $exception->getStatusCode()
      : Response::HTTP_INTERNAL_SERVER_ERROR;

    $response = new Response($html, $status, ['Content-Type' => 'text/html']);

    // Zusätzliche Header wie Retry-After beibehalten, falls vorhanden.
    if ($exception instanceof HttpExceptionInterface) {
      $response->headers->add($exception->getHeaders());
    }

    // Antwort senden und weitere Subscriber (inkl. Core) stoppen.
    $event->setResponse($response);
    $event->stopPropagation();
  }

  /**
   * Liest web/500.html und ersetzt das {{ message }}-Token falls vorhanden.
   */
  protected function buildHtml(string $message): string {
    $template = DRUPAL_ROOT . '/500.html';

    if (is_readable($template)) {
      $html = file_get_contents($template);
      return str_replace('{{ message }}', Markup::create($message), $html);
    }

    // Sichere Fallback-Lösung, falls Template fehlt.
    return '<html><head><title>500</title></head><body>'
      . Markup::create($message)
      . '</body></html>';
  }

  /**
   * TRUE, wenn das Fehlerlevel auf "Verbose" steht.
   *
   * Spiegelung von \Drupal\Core\EventSubscriber\FinalExceptionSubscriber::isErrorLevelVerbose().
   */
  protected function isErrorLevelVerbose(): bool {
    return $this->configFactory
      ->get('system.logging')
      ->get('error_level') === ERROR_REPORTING_DISPLAY_VERBOSE;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    // Priorität -250 → läuft direkt vor Drupals FinalExceptionSubscriber (-256).
    $events[KernelEvents::EXCEPTION][] = ['onException', -250];
    return $events;
  }

}

Diese Subscriber-Klasse, SeoExceptionSubscriber, fängt alle nicht abgefangenen Exceptions innerhalb von Drupal ab. Sie prüft, ob Ihre Drupal-Seite auf „Verbose“-Fehlerberichterstattung eingestellt ist. Falls ja, lässt sie Drupal die Standard-Fehlermeldungen anzeigen. Ist die Seite jedoch nicht im „Verbose“-Modus (typisch für Produktionsumgebungen), wird die Exception abgefangen und eine benutzerfreundliche Fehlermeldung vorbereitet.

Sie liest speziell Ihre individuelle 500.html-Datei, die sich im Root-Verzeichnis Ihrer Drupal-Installation befindet. Die Fehlermeldung wird dynamisch über das Platzhalter-Token {{ message }} in den HTML-Inhalt eingefügt, wodurch die angezeigte Seite sowohl informativ als auch optisch konsistent bleibt.

Darüber hinaus sorgt der Subscriber dafür, dass Drupals Standard-Error-Handler nicht weiter ausgeführt wird. So wird die Drupal-Fehlerseite nicht über Ihre eigene HTML-Seite geschrieben. Mit einer Priorität von -250 wird der Subscriber direkt vor Drupals Core-Fehlerbehandler ausgeführt und überschreibt somit das Standardverhalten von Drupal.

Für Ihre lokale Entwicklungsumgebung können Sie Einstellungen setzen, damit Fehler statt der 500-Fehlerseite angezeigt werden.
settings.php:

$config['system.logging']['error_level'] = 'verbose';

error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);

Manchmal ist Drupal nicht erreichbar, dann müssen Sie zusätzliche Konfigurationen für Ihren Webserver oder Ihre Cloud vornehmen.

500-Fehlerseite in Apache hinzufügen

Um Ihre vorhandene 500.html-Fehlerseite aus dem Dokumentenstamm Ihrer Seite bei HTTP-Fehlern 500–504 auszuliefern, müssen Sie Apache entsprechend konfigurieren. Nachfolgend zwei einfache Möglichkeiten:

1. Verwendung der Apache Virtual Host-Konfiguration (empfohlen)

Bearbeiten Sie die Virtual Host-Konfigurationsdatei Ihrer Seite (normalerweise unter /etc/apache2/sites-available/your-site.conf) und fügen Sie folgende Direktiven innerhalb des <VirtualHost>-Blocks hinzu:

ErrorDocument 500 /500.html
ErrorDocument 501 /500.html
ErrorDocument 502 /500.html
ErrorDocument 503 /500.html
ErrorDocument 504 /500.html

Anschließend Apache neu laden, um die Änderungen zu übernehmen:

sudo systemctl reload apache2

2. Verwendung der .htaccess-Datei

Wenn Sie lieber die .htaccess-Datei (im Dokumentenstamm Ihrer Website) nutzen, fügen Sie diese Zeilen ein:

ErrorDocument 500 /500.html
ErrorDocument 501 /500.html
ErrorDocument 502 /500.html
ErrorDocument 503 /500.html
ErrorDocument 504 /500.html

Stellen Sie sicher, dass die Datei 500.html im Root-Verzeichnis Ihrer Seite liegt und für Apache zugänglich und lesbar ist. Nach Anwendung dieser Einstellungen zeigt Apache für Fehler 500 bis 504 stets Ihre gestaltete HTML-Fehlerseite an.

500-Fehlerseite in Nginx hinzufügen

Um Nginx so zu konfigurieren, dass Ihre eigene 500.html-Fehlerseite im Root-Verzeichnis Ihrer Seite für HTTP-Fehler (500–504) angezeigt wird, passen Sie die Server-Konfiguration wie folgt an:

Bearbeiten Sie die Nginx-Konfigurationsdatei Ihrer Seite (meist unter /etc/nginx/sites-available/your-site.conf) und fügen Sie diese Direktiven im server {}-Block ein:

error_page 500 501 502 503 504 /500.html;
location = /500.html {
    root /var/www/html;
    internal;
}

Stellen Sie sicher, dass der Pfad (/var/www/html) auf das Dokumentenstammverzeichnis Ihrer Seite mit der 500.html-Datei zeigt. Nach der Änderung Nginx-Konfiguration neu laden:

sudo nginx -s reload

Nun zeigt Nginx für HTTP-Statuscodes 500 bis 504 stets Ihre eigene HTML-Fehlerseite an.