Zend Framework 3 错误处理

Zend Framework 3 error handling

我正在尝试处理 ZF3 中 CheckAccess 插件的错误。

插件在模块的 onBootstrap 方法中是这样附加的

class Module {
    public function onBootstrap()
    {
        ...
        $em->attach(MvcEvent::EVENT_DISPATCH, new Plugin\CheckAccess($sm), 2);
        ...
    }
}

当我需要将未登录的用户从某个页面重定向到登录页面时,我正是在插件的 __invoke() 中做的:

if ($user->isGuest()) {
        $rh = new RouteHelper($e->getRouter(), $e->getRouteMatch());
        $url = $rh->frontend('auth', 'login') . '?request=' . urlencode($request->getRequestUri());

        throw new HttpRedirectException(HttpRedirectException::SEE_OTHER_303, $url);
    } else {
        throw new HttpClientException(HttpClientException::FORBIDDEN_403);
    }
}

问题是那些异常导致应用程序崩溃。我的意思是框架中没有对此类异常的任何处理。而且我没有在文档中找到任何帮助。我该如何解决?我想应该有一些关于 "correct" zf 中访问检查和访问异常处理的最佳实践。

我从未见过有人为此抛出异常,尤其是 HttpRedirectException 和 HttpClientException,所以不幸的是我现在没有答案。

您可以通过更简洁、更轻松的方式实现您想要的效果,而无需抛出异常。你可以这样做:

$sharedEventManager->attach(AbstractActionController::class, 
                MvcEvent::EVENT_DISPATCH, [$this, 'onDispatch'], 100);

然后检查用户是否登录,并基于此使用此重定向方法:

/**
 * Event listener method for the 'Dispatch' event. We listen to the Dispatch
 * event to call the access filter. The access filter allows to determine if
 * the current visitor is allowed to see the page or not. If he/she
 * is not authorized and is not allowed to see the page, we redirect the user 
 * to the login page.
 */
public function onDispatch(MvcEvent $event)
{
    // Get controller and action to which the HTTP request was dispatched.
    $controller = $event->getTarget();
    $controllerName = $event->getRouteMatch()->getParam('controller', null);
    $actionName = $event->getRouteMatch()->getParam('action', null);

    // Convert dash-style action name to camel-case.
    $actionName = str_replace('-', '', lcfirst(ucwords($actionName, '-')));

    // Get the instance of AuthManager service.
    $authManager = $event->getApplication()->getServiceManager()->get(AuthManager::class);

    // Execute the access filter on every controller except AuthController
    // (to avoid infinite redirect).
    if ($controllerName!=AuthController::class)
    {
        $result = $authManager->filterAccess($controllerName, $actionName);

        if ($result==AuthManager::AUTH_REQUIRED) {

            // Remember the URL of the page the user tried to access. We will
            // redirect the user to that URL after successful login.
            $uri = $event->getApplication()->getRequest()->getUri();

            // Make the URL relative (remove scheme, user info, host name and port)
            // to avoid redirecting to other domain by a malicious user.
            $uri->setScheme(null)
                ->setHost(null)
                ->setPort(null)
                ->setUserInfo(null);
            $redirectUrl = $uri->toString();

            // Redirect the user to the "Login" page.
            return $controller->redirect()->toRoute('login', [], 
                    ['query'=>['redirectUrl'=>$redirectUrl]]);
        }
        else if ($result==AuthManager::ACCESS_DENIED) {
            // Redirect the user to the "Not Authorized" page.
            return $controller->redirect()->toRoute('not-authorized');
        }
    }
}

如您所见,这只是一个示例,但非常简单明了,您也检查了 ACL,无需抛出异常...

然而,为了拦截所有异常,我会做(并且我会做)的是附加以下内容:

// The "init" method is called on application start-up and 
    // allows to register an event listener.
    public function init(ModuleManager $manager)
    {
        // Get event manager.
        $eventManager = $manager->getEventManager();
        $sharedEventManager = $eventManager->getSharedManager();
        // Register the event listener method. 
        $sharedEventManager->attach(__NAMESPACE__, MvcEvent::EVENT_DISPATCH_ERROR,
                                    [$this, 'onError'], 100);
        $sharedEventManager->attach(__NAMESPACE__, MvcEvent::EVENT_RENDER_ERROR, 
                                    [$this, 'onError'], 100);
    }

    // Event listener method.
    public function onError(MvcEvent $event)
    {
        // Get the exception information.
        $exception = $event->getParam('exception');
        if ($exception!=null) {
            $exceptionName = $exception->getMessage();
            $file = $exception->getFile();
            $line = $exception->getLine();
            $stackTrace = $exception->getTraceAsString();
        }
        $errorMessage = $event->getError();
        $controllerName = $event->getController();

        // Prepare email message.
        $to = 'admin@yourdomain.com';
        $subject = 'Your Website Exception';

        $body = '';
        if(isset($_SERVER['REQUEST_URI'])) {
            $body .= "Request URI: " . $_SERVER['REQUEST_URI'] . "\n\n";
        }
        $body .= "Controller: $controllerName\n";
        $body .= "Error message: $errorMessage\n";
        if ($exception!=null) {
            $body .= "Exception: $exceptionName\n";
            $body .= "File: $file\n";
            $body .= "Line: $line\n";
            $body .= "Stack trace:\n\n" . $stackTrace;
        }

        $body = str_replace("\n", "<br>", $body);

        // Send an email about the error.
        mail($to, $subject, $body);
    }

这会捕获所有错误,甚至会向您发送电子邮件!哈哈

我希望这些片段能帮助您了解如何更好地使用 ZF3 进行开发。

这些片段的来源是 olegkrivtsov