Dodavanje stranice za grešku 500 u Drupalu pomoću Event Subscriber-a
Često se suočavamo sa stranicom greške 500 kada Drupal, servisi ili drugi sajtovi nisu dostupni. Kada vidimo grešku 500 (ili 501–504). U Drupalu koristimo Exceptions da proverimo da li je neki kritičan kod izvršen. Ako dođe do greške, na primer pri HTTP zahtevu ka drugom sajtu, Drupal će prikazati ovu grešku: "The website encountered an unexpected error. Please try again later":

Nije dobro imati WSOD (white screen of death) na svom sajtu, zato hajde da to poboljšamo i prikažemo stilizovanu HTML stranicu umesto toga.
Imam stilizovanu 500.html stranicu u root folderu sajta, iz performansnih razloga. Možemo koristiti i stilizovanu Drupal stranicu za 500 grešku, ali takođe koristim istu stranicu i za 503/504 greške u Apache/Nginx i lakše je održavati ovu stranicu kao jedan HTML fajl na jednom mestu.

Sada treba da dodamo kod u naš prilagođeni modul DrupalBook Custom (drupalbook_custom). U drupalbook_custom.services.yml treba da dodamo Event Subscriber:
services:
drupalbook_custom.exception_subscriber:
class: Drupal\drupalbook_custom\EventSubscriber\SeoExceptionSubscriber
arguments: ['@config.factory']
tags:
- { name: event_subscriber, priority: -250 }
Ovde je kod za 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;
/**
* Zamenjuje Drupal\Core\EventSubscriber\FinalExceptionSubscriber 500 grešku.
*/
class SeoExceptionSubscriber implements EventSubscriberInterface {
use StringTranslationTrait;
/**
* Konfiguracija za podešavanja.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected ConfigFactoryInterface $configFactory;
public function __construct(ConfigFactoryInterface $config_factory) {
$this->configFactory = $config_factory;
}
/**
* Obradjuje sve neuhvaćene exception-e i vraća prilagođeni HTML odgovor.
*/
public function onException(ExceptionEvent $event): void {
// Prikazati standardni Drupal stack trace kada je sajt u VERBOSE režimu.
if ($this->isErrorLevelVerbose()) {
return;
}
$exception = $event->getThrowable();
// Osnovna poruka (proširiti za verbose režim ako treba).
$error = Error::decodeException($exception);
$message = new FormattableMarkup('@message', [
'@message' => $error['!message'] ?? $this->t('The website encountered an unexpected error.'),
]);
$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']);
// Sačuvati dodatne zaglavlja kao što je Retry-After ako su prisutna.
if ($exception instanceof HttpExceptionInterface) {
$response->headers->add($exception->getHeaders());
}
// Pošalji odgovor i zaustavi dalje Event Subscriber-e (uključujući core).
$event->setResponse($response);
$event->stopPropagation();
}
/**
* Čita web/500.html i ubacuje {{ message }} token ako postoji.
*/
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);
}
// Bezbedan fallback ako nedostaje template.
return '<html><head><title>500</title></head><body>'
. Markup::create($message)
. '</body></html>';
}
/**
* TRUE kada je nivo greške podešen na “Verbose”.
*
* Ogledalo \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 {
// Prioritet -250 → izvršava se neposredno pre core FinalExceptionSubscriber (-256).
$events[KernelEvents::EXCEPTION][] = ['onException', -250];
return $events;
}
}
Ova subscriber klasa, SeoExceptionSubscriber
, presreće sve neuhvaćene exception-e unutar Drupala. Proverava da li je vaš Drupal sajt podešen na detaljni prikaz grešaka (verbose mode), i ako jeste, dozvoljava Drupalu da prikaže svoje standardne detaljne poruke o grešci. Međutim, ako sajt nije u verbose režimu (što je tipično za produkciju), presreće exception i priprema korisniku prijatniju poruku o grešci.
Konkretno, čita vaš prilagođeni 500.html
fajl koji se nalazi u root folderu vaše Drupal instalacije. Dinamički ubacuje poruku o grešci u HTML sadržaj tako što zamenjuje placeholder {{ message }}
, osiguravajući da prikazana stranica bude informativna i vizuelno dosledna.
Dodatno, subscriber eksplicitno sprečava Drupal-ov podrazumevani handler za greške da dalje procesira događaj. Ovo osigurava da Drupal-ova ugrađena error stranica ne prepiše vaš prilagođeni HTML. Definisanjem subscriber-a sa prioritetom -250
, izvršava se neposredno pre ugrađenog Drupal error subscriber-a, efektivno nadjačavajući Drupal-ovo podrazumevano ponašanje.
Za lokalno okruženje možete dodati podešavanja za prikazivanje grešaka umesto 500 error strane.
settings.php:
$config['system.logging']['error_level'] = 'verbose';
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
Ponekad Drupal nije dostupan, pa će biti potrebno da dodatno podesite vaš web server ili Cloud okruženje.
Dodavanje 500 error strane u Apache
Da biste prikazali postojeću 500.html
stranicu iz root direktorijuma vašeg sajta svaki put kada dođe do HTTP grešaka 500–504, potrebno je podesiti Apache. Evo dva jednostavna načina za to:
1. Korišćenje Apache Virtual Host konfiguracije (preporučeno)
Izmenite konfiguracioni fajl vašeg sajta (najčešće /etc/apache2/sites-available/your-site.conf
) i dodajte sledeće direktive unutar <VirtualHost>
bloka:
ErrorDocument 500 /500.html
ErrorDocument 501 /500.html
ErrorDocument 502 /500.html
ErrorDocument 503 /500.html
ErrorDocument 504 /500.html
Zatim restartujte Apache da bi se promene primenile:
sudo systemctl reload apache2
2. Korišćenje .htaccess
fajla
Ako želite da koristite .htaccess
fajl (u root direktorijumu sajta), dodajte sledeće linije:
ErrorDocument 500 /500.html
ErrorDocument 501 /500.html
ErrorDocument 502 /500.html
ErrorDocument 503 /500.html
ErrorDocument 504 /500.html
Uverite se da je fajl 500.html
postavljen u root direktorijumu sajta i da je Apache može pročitati. Nakon ovih podešavanja, Apache će prikazivati vašu stilizovanu HTML error stranicu za greške od 500 do 504.
Dodavanje 500 error strane u Nginx
Da biste podesili Nginx da prikazuje vašu prilagođenu 500.html
stranicu iz root direktorijuma sajta za HTTP greške (500–504), izmenite Nginx konfiguraciju vašeg sajta na sledeći način:
Otvorite konfiguracioni fajl vašeg sajta (najčešće /etc/nginx/sites-available/your-site.conf
) i dodajte sledeće direktive unutar server {}
bloka:
error_page 500 501 502 503 504 /500.html;
location = /500.html {
root /var/www/html;
internal;
}
Proverite da li /var/www/html
odgovara root direktorijumu vašeg sajta gde se nalazi 500.html
. Nakon izmena, restartujte Nginx da bi se promene primenile:
sudo nginx -s reload
Sada će Nginx prikazivati vašu prilagođenu HTML stranicu za greške od 500 do 504.