Drupal-ում 500 սխալի էջի ավելացում Event Subscriber-ի միջոցով
Հաճախ մենք հանդիպում ենք 500 սխալի էջի, երբ Drupal-ը, ծառայությունները կամ այլ կայքերը հասանելի չեն: Երբ տեսնում ենք 500 (կամ 501-504) սխալի էջ։ Drupal-ում մենք օգտագործում ենք Exception-ներ՝ որոշ կարևոր կոդի կատարումը ստուգելու համար։ Եթե առաջանում է սխալ, օրինակ՝ HTTP հարցման ժամանակ այլ կայք, Drupal-ը կցուցադրի այս սխալը՝ "Կայքում տեղի ունեցավ անսպասելի սխալ։ Խնդրում ենք փորձել ավելի ուշ":

Կայքում "մահացած սպիտակ էկրան" (WSOD, white screen of death) ունենալը լավ տարբերակ չէ, այդ պատճառով եկեք այն բարելավենք ու ցուցադրենք ձևավորված HTML էջ դրա փոխարեն։
Իմ կայքի արմատում (root) ունեմ ձևավորված 500.html էջ՝ արտադրողականության նկատառումներով։ Կարելի է օգտագործել ձևավորված Drupal էջ 500 սխալի համար, բայց ես նաև նույն էջը կօգտագործեմ 503/504 սխալի դեպքում Apache/Nginx-ում և հեշտ կլինի այս էջը մեկ տեղում, որպես միակ HTML էջ պահպանելը։

Հիմա անհրաժեշտ է կոդ ավելացնել մեր custom մոդուլում՝ DrupalBook Custom (drupalbook_custom): drupalbook_custom.services.yml ֆայլում պետք է ավելացնել Event Subscriber՝
services:
drupalbook_custom.exception_subscriber:
class: Drupal\drupalbook_custom\EventSubscriber\SeoExceptionSubscriber
arguments: ['@config.factory']
tags:
- { name: event_subscriber, priority: -250 }
Սա է կոդը՝ 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;
/**
* Փոխարինում է Drupal\Core\EventSubscriber\FinalExceptionSubscriber 500 սխալի էջը։
*/
class SeoExceptionSubscriber implements EventSubscriberInterface {
use StringTranslationTrait;
/**
* Կարգավորումներ։
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected ConfigFactoryInterface $configFactory;
public function __construct(ConfigFactoryInterface $config_factory) {
$this->configFactory = $config_factory;
}
/**
* Վերամշակում է բոլոր չբռնված բացառությունները և վերադարձնում custom HTML պատասխան։
*/
public function onException(ExceptionEvent $event): void {
// Ցուցադրել ստանդարտ Drupal stack trace եթե կայքը VERBOSE ռեժիմում է։
if ($this->isErrorLevelVerbose()) {
return;
}
$exception = $event->getThrowable();
// Հիմնական հաղորդագրություն (հնարավոր է ավելացնել մանրամասն ռեժիմում)։
$error = Error::decodeException($exception);
$message = new FormattableMarkup('@message', [
'@message' => $error['!message'] ?? $this->t('Կայքում տեղի ունեցավ անսպասելի սխալ։'),
]);
$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']);
// Պահպանել լրացուցիչ վերնագրերը, օրինակ՝ Retry-After։
if ($exception instanceof HttpExceptionInterface) {
$response->headers->add($exception->getHeaders());
}
// Ուղարկել պատասխանը և կանգնեցնել հետագա subscriber-ների աշխատանքը։
$event->setResponse($response);
$event->stopPropagation();
}
/**
* Կարդում է web/500.html-ը և ներմուծում է {{ message }} token-ը։
*/
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);
}
// Պարզ fallback, եթե template-ը չկա։
return '<html><head><title>500</title></head><body>'
. Markup::create($message)
. '</body></html>';
}
/**
* TRUE, եթե սխալի մակարդակը "Verbose" է։
*
* Կրկնում է \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 {
// Priority -250 → աշխատում է core-ի FinalExceptionSubscriber-ից անմիջապես առաջ (-256)։
$events[KernelEvents::EXCEPTION][] = ['onException', -250];
return $events;
}
}
Այս subscriber դասը՝ SeoExceptionSubscriber
, բռնում է Drupal-ի բոլոր չմշակված բացառությունները։ Այն ստուգում է՝ արդյո՞ք Ձեր Drupal կայքը գտնվում է մանրամասն սխալների ցուցադրման (verbose) ռեժիմում, և եթե այո, թույլ է տալիս Drupal-ին ցուցադրել իր ստանդարտ մանրամասն սխալները։ Իսկ եթե ոչ (արտադրողական միջավայրի համար), այն բռնում է բացառությունը և ձևավորում օգտվողին բարեկեցիկ սխալային հաղորդագրություն։
Մասնավորապես, այն կարդում է Ձեր custom 500.html
ֆայլը, որը գտնվում է Drupal-ի ինստալացիայի root-ում։ Այն դինամիկ կերպով հաղորդագրությունը դնում է HTML բովանդակության մեջ՝ փոխարինելով {{ message }}
placeholder-ը, այսպիսով ստացվող էջը կլինի թե՛ ինֆորմատիվ, թե՛ դիզայնով համապասխան կայքին։
Բացի այդ, subscriber-ը հստակ կանգնեցնում է Drupal-ի ստանդարտ սխալի մշակումը։ Սա երաշխավորում է, որ Drupal-ի ներքին սխալի էջը չի վերագրի Ձեր custom HTML էջը։ Event subscriber-ը priority -250
-ով աշխատում է հենց core-ի ներդրված subscriber-ից առաջ՝ վերագրելով core-ի վարքագիծը։
Տեղային միջավայրի համար կարող եք ավելացնել կարգավորումներ՝ տեսնելու համար սխալները 500 էջի փոխարեն.
settings.php՝
$config['system.logging']['error_level'] = 'verbose';
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
Որոշ դեպքերում Drupal-ը կարող է անհասանելի լինել, և այդ դեպքում անհրաժեշտ կլինի հավելյալ կարգավորումներ անել Ձեր վեբ սերվերի կամ Cloud-ի համար։
500 սխալի էջի ավելացում Apache-ում
Որպեսզի Ձեր կայքի արմատից (document root) մատուցվի 500.html
էջը 500–504 HTTP սխալների դեպքում, անհրաժեշտ է կարգավորել Apache-ը հետևյալ կերպ։ Ստորև ներկայացված են երկու պարզ տարբերակ՝
1. Օգտագործելով Apache Virtual Host Configuration (նախընտրելի)
Խմբագրեք Ձեր կայքի վիրտուալ հոսթի կոնֆիգի ֆայլը (սովորաբար՝ /etc/apache2/sites-available/your-site.conf
) և <VirtualHost>
բլոկի մեջ ավելացրեք հետևյալ տողերը՝
ErrorDocument 500 /500.html
ErrorDocument 501 /500.html
ErrorDocument 502 /500.html
ErrorDocument 503 /500.html
ErrorDocument 504 /500.html
Հետո վերագործարկեք Apache-ը՝ փոփոխությունները ուժի մեջ մտցնելու համար.
sudo systemctl reload apache2
2. Օգտագործելով .htaccess
ֆայլը
Եթե նախընտրում եք .htaccess
ֆայլը (գտնվում է կայքի արմատում), պարզապես ավելացրեք այս տողերը՝
ErrorDocument 500 /500.html
ErrorDocument 501 /500.html
ErrorDocument 502 /500.html
ErrorDocument 503 /500.html
ErrorDocument 504 /500.html
Համոզվեք, որ 500.html
ֆայլը տեղադրված է կայքի արմատում, և այն հասանելի ու ընթերցելի է Apache-ի համար։ Այս կարգավորումներից հետո Apache-ը 500-504 սխալների դեպքում մշտապես կցուցադրի Ձեր ձևավորված HTML սխալի էջը։
500 սխալի էջի ավելացում Nginx-ում
Որպեսզի Nginx-ը մատուցի Ձեր custom 500.html
սխալի էջը, որը գտնվում է կայքի root-ում 500–504 HTTP սխալների դեպքում, անհրաժեշտ է թարմացնել կայքի Nginx կոնֆիգի ֆայլը՝
Խմբագրեք կայքի Nginx կոնֆիգի ֆայլը (օրինակ՝ /etc/nginx/sites-available/your-site.conf
) և server {}
բլոկում ավելացրեք հետևյալ տողերը՝
error_page 500 501 502 503 504 /500.html;
location = /500.html {
root /var/www/html;
internal;
}
Համոզվեք, որ ճանապարհը (/var/www/html
) ճիշտ է և մատնանշում է Ձեր կայքի document root-ը, որտեղ տեղադրված է 500.html
ֆայլը։ Փոփոխություններից հետո վերագործարկեք Nginx-ը՝ կարգավորումները ուժի մեջ մտցնելու համար՝
sudo nginx -s reload
Այժմ Nginx-ը կհայտնաբերելով 500–504 HTTP սխալները՝ մշտապես կցուցադրի Ձեր custom HTML սխալի էջը։