Hallo, ich heiße Matthias Zeis - schön, dass Sie den Weg zu meiner Übersetzung von ZFSTDE gefunden haben!
Falls Sie mehr über Magento 2 oder meine Arbeit als Technical Lead bei LimeSoda erfahren möchten, kommen Sie doch auf meiner Website vorbei.
Inhaltsverzeichnis
Unsere einfache, kleine Anwendung wird erwachsen! Um den Abschnitt des Buches abzuschließen, der Sie mit dem Zend Framework und dessen Grundlagen beim Aufsetzen einer Anwendung bekannt machen soll, werfen wir nun noch einen Blick auf die Fehlerbehandlung.
Wie wir im letzten
Kapitel festgelegt haben, wirft
Zend_Controller_Front
nur Ausnahmen, wenn wir uns
im Entwicklungs- oder Testmodus befinden. Im Produktivbetrieb sollten den
Benutzern Fehler und Ausnahmen nicht angezeigt werden. Wenn etwas schief
geht, können wir den Benutzer allerdings nicht mit einer leeren
Browserseite abspeisen - er wird verwirrt, vielleicht sogar ratlos zurück
bleiben. Wir sollten den Benutzer stattdessen darüber informieren, dass
ein Problem existiert, dass es uns extrem leid tut, dass wir den
zuständigen Entwickler sogleich foltern und diese kleine Panne beheben
werden, sobald die Folter den gewünschten Effekt erzielt hat.
Um das zu erreichen,
nimmt Zend_Controller_Front
an, dass wir einen
neuen Controller erzeugen, um diese Situation zu handhaben - den
ErrorController, um genau zu sein. Schlägt die Erzeugung des
ErrorController
fehl, wird sich unsere Anwendung
darüber beschweren, dass er fehlt, besonders wenn der Fehler von einer URL
kommt, die auf einen nicht existierenden Ort verweist, weswegen eine
404-Meldung zurückgegeben werden sollte.
Die Behandlung von
Ausnahmen erfolgt durch ein Front-Controller-Plugin namens
Zend_Controller_Plugin_ErrorHandler
.
Wir werden die Fehlerberichterstattung für den Benutzer mit dieser minimalen Klasse möglichst einfach halten.
<?php
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
}
}
Wie wir bereits
festgestellt haben, rendern alle Controller-Actions automatisch eine
zugehörige View. Da wir eine Methode
errorAction()
in einem
ErrorController
haben, wird das View-Skript in der
Datei /application/views/scripts/error/error.phtml
gerendert. Aber nur, wenn sie existiert - also fügen Sie sie nun
hinzu!
<?php echo $this->doctype() ?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<?php echo $this->headMeta() ?>
<meta name="language" content="en" />
<title>Oops! There's Been A Problem!</title>
</head>
<body>
<h1>An Error Has Occurred</h1>
<p>We're truly sorry, but we cannot complete your request at this
time.</p>
<p>If it's any consolation, we have scheduled a new appointment
for our development team leader in Torture Chamber #7 to encourage
his colleagues to investigate this incident.</p>
</body>
</html>
Ach, wenn es bloß so einfach wäre...
Wechseln Sie zurück zum
Browser und versuchen Sie, http://helloworld.tld/route/does/not/exist
aufzurufen. Da diese URL keiner Route (und damit keinem Controller)
entspricht, sollte die Anzeige dieser Fehlernachricht ausgelöst
werden.
Anstatt unserer Fehlerseite wurde eine Ausnahme-Meldung samt Details an den Browser gesendet.
Der
ErrorController
wurde so konzipiert, dass er nur
anspringt, wenn der Front-Controller so eingestellt ist, dass er nie eine
Ausnahme wirft - ausgenommen bei Ausnahmen, die geworfen werden müssen,
weil jemand darauf vergessen hat, den
ErrorController
hinzuzufügen! Tatsächlich entstammt
dieser Situation auch die irritierende Ausnahme-Meldung, dass kein
ErrorController gefunden wurde. Um den
ErrorController
zu testen, müssen wir eine
temporäre Veränderung an /config/application.ini
vornehmen, die unterbindet, dass
Zend_Controller_Front
Ausnahmen wirft. Dazu ändern
wir den Wert der letzte Zeile "resources.frontController.throwExceptions"
auf 0 (bzw. false). Dadurch ist sichergestellt, dass das
ErrorHandler-Plugin eine Fehlerseite ohne Ausnahmen ausliefern
kann.
[production] phpSettings.display_startup_errors = 0 phpSettings.display_errors = 0 bootstrap.path = APPLICATION_ROOT "/library/ZFExt/Bootstrap.php" bootstrap.class = "ZFExt_Bootstrap" resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" resources.view.encoding = "UTF-8" resources.view.doctype = "XHTML1_STRICT" resources.view.contentType = "text/html;charset=utf-8" resources.modifiedFrontController.contentType = "text/html;charset=utf-8" [staging : production] [testing : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 1 [development : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.throwExceptions = 0
Sie glauben vielleicht, dass wir nun aufhören und still und heimlich aus Folterkammer #7 flüchten können, aber da irren Sie sich. Wenn Sie einen genaueren Blick unter die Haube werfen, werden Sie feststellen, dass unsere Fehler sehr vage sind und wir - was schlimmer ist - auf die HTTP-Requests mit einem "HTTP/1.1 200 OK"-Header antworten. Nennen Sie mich dumm, aber haben wir nicht eben erst unseren Fehler eingestanden, indem wir dem Benutzer eine Fehlermeldung präsentiert haben? Wenn in unserer Anwendung ein Fehler auftritt, dann sollte niemals so ein Status-Code und so eine Nachricht zurückgegeben werden.
Das scheint vielleicht nicht sehr wichtig zu sein, aber das ist es. Nicht jeder Teril unserer Anwendung wird unbedingt Joe Bloggs in seinen Browser geliefert. Requests können von anderen Anwendungen kommen, die sich beim Feststellen von Fehlern eher auf HTTP-Response-Codes verlassen als auf Ihre unverhohlene Grausamkeit Entwicklern gegenüber. Auf jeden Fall müssen Sie mit Ihrer internen Anwendungsüberprüfung fertig werden. Werden Sie Probleme aufspüren können, wenn laut Ihren Webserverlogs jede einzelne Anfrage erfolgreich war? Dann gibt es noch das große Problem namens RFC 2616 "Hypertext Transfer Protocol -- HTTP/1.1", das für den Bereich der 2xx Status-Codes erklärt: "This class of status code indicates that the client's request was successfully received, understood, and accepted". Das W3C hat mit anderen Worten einen ganz speziellen Raum mit dem Namen "Folterkammer aus der Hölle #1" für diejenigen, deren Anwendungen behaupten, allmächtig zu sein.
Ein fehlgeschlagenes
Routing ist kein Erfolg, sondern es bedeutet, dass entweder das Routing
nicht funktioniert oder - was wahrscheinlicher ist - der Benutzer eine
ungültige URL angefordert hat. Da das Verwenden einer falschen URL ein
Benutzerfehler ist, sollten wir unseren Teamleiter vermutlich noch nicht
in die Folterkammer schicken. Stattdessen sollten wir dem Besucher
(höflich) erklären, dass er sich geirrt hat und einen 404 "Not
Found"-Status für den Fall einfügen, dass der Benutzer eine Maschine ist.
Um das umzusetzen, müssen wir in unserem
ErrorController
ein paar Kontrollen
durchführen.
<?php
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
$error = $this->_getParam('error_handler');
switch ($error->type)
{
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
$this->getResponse()->setHttpResponseCode(404);
$this->view->statusCode = 404;
break;
default:
$this->getResponse()->setHttpResponseCode(500);
$this->view->statusCode = 500;
}
}
}
Im obigen Codeausschnitt schnappen wir uns das ErrorHandler-Plugin und lesen den Wert des Fehlertyps aus. Wenn der Fehler einem Routing-Problem entspricht, setzen wir den Statuscode 404, um klarzustellen, dass es sich nicht um einen Fehler von uns handelt und der Pfad in unserer Anwendung schlicht nicht existiert. Ansonsten setzen wir für alle anderen Fehler den HTTP-Status-Code 500. Der Status-Code 500 wird im Header durch die Meldung "Internal Server Error" ergänzt. Aktualisieren wir also unser vorhandenes Fehler-Template.
<?php echo $this->doctype() ?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<?php echo $this->headMeta() ?>
<meta name="language" content="en" />
<title>Oops! There's Been A Problem!</title>
</head>
<body>
<h1>An Error Has Occurred</h1>
<?php if ($this->statusCode == 500): ?>
<p>We're truly sorry, but we cannot complete your request at this
time.</p>
<p>If it's any consolation, we have scheduled a new appointment
for our development team leader in Torture Chamber #7 to encourage
his colleagues to investigate this incident.</p>
<?php else: ?>
<p>We're truly sorry, but the page you are trying to locate
does not exist.</p>
<p>Please double check the requested URL or consult your local
Optometrist.</p>
<?php endif; ?>
</body>
</html>
Kundenbindung ist eindeutig nicht ein vorrangiges Ziel dieses Kapitels.
Wenn Sie mit dem Browser eine ungültige URL aufrufen, sollten Sie die entsprechende Meldung zusammen mit dem Status-Code 404 im Header erhalten. Wenn Sie etwas tun, um eine andere Ausnahme zu werfen, sollten Sie den Status-Code 500 mit der zugehörigen HTML-Meldung erhalten.
Fehlerbehandlung ist
keine schwierige, aber eine notwendige Aufgabe - besonders dann, wenn
unsere Anwendung von anderen anwendungsgesteuerten Clients besucht werden
könnte, die sich nicht auf von Menschen lesbare HTML-Seiten, sondern auf
die Kommunikation mittels korrekter Status-Codes und -Header verlassen, um
abzuklären, ob ein HTTP-Request erfolgreich war oder nicht. Ich empfehle
Ihnen wärmstens, darauf zu achten, dass Ihre Anwendung immer korrekte
Header und Codes sendet. Der ErrorController
ist
ziemlich einfach gehalten, aber man kann sich leicht denken, dass wir ihn
um das Loggen von Fehlern oder E-Mail-Benachrichtigungen erweitern
könnten.