Error handling 如何在ZF2中使用自定义异常页面?

Error handling 如何在ZF2中使用自定义异常页面?,error-handling,zend-framework2,redirect,Error Handling,Zend Framework2,Redirect,当不允许用户访问特定资源时,我需要将用户从名为Admin的模块的Module.php中重定向到错误页面(view/error/403.phtml)。我一直在寻找解决这个问题的办法,但到目前为止没有成功。我找到的最好的答案是,被接受的答案对我不起作用(我目前无法向链接的问题添加评论,因为我没有所需的信誉级别)-页面显示时,好像根本没有重定向,用户可以访问它。我试着用一个简单的模具替换重定向代码测试isAllowed()是否正常工作,并且它正确显示空白页,因此问题在于重定向本身 Module.php

当不允许用户访问特定资源时,我需要将用户从名为
Admin
的模块的
Module.php
中重定向到错误页面(
view/error/403.phtml
)。我一直在寻找解决这个问题的办法,但到目前为止没有成功。我找到的最好的答案是,被接受的答案对我不起作用(我目前无法向链接的问题添加评论,因为我没有所需的信誉级别)-页面显示时,好像根本没有重定向,用户可以访问它。我试着用一个简单的
模具替换重定向代码
测试
isAllowed()
是否正常工作,并且它正确显示空白页,因此问题在于重定向本身

Module.php
中的相关代码是:

public function onBootstrap(MvcEvent $e)
{
    $this->initAcl($e);
    $eventManager = $e->getApplication()->getEventManager();

    $eventManager->attach('route', array($this, 'checkAcl'));
    $moduleRouteListener = new ModuleRouteListener();
    $moduleRouteListener->attach($eventManager);
}

public function checkAcl(MvcEvent $e)
{
    // ...

    if (!$this->acl->isAllowed($userRole, $controller, $privilege))
    {
        $response = $e->getResponse();
        $response->setHeaders($response->getHeaders()->addHeaderLine('Location', $e->getRequest()->getBaseurl() . '/error/403'));
        $response->setStatusCode(403);
        $response->sendHeaders();
    }

    // ...
}
module.config.php

'view_manager' => array(
    'display_exceptions' => true,
    'exception_template' => 'error/403',
    'template_map' => array(
        'layout/layout'           => __DIR__ . '/../view/layout/admin_layout.phtml',
        'error/403'               => __DIR__ . '/../view/error/403.phtml',
        'error/404'               => __DIR__ . '/../view/error/404.phtml',
        'error/index'             => __DIR__ . '/../view/error/index.phtml',
    ),
    'template_path_stack' => array(
        'Admin' => __DIR__ . '/../view',
    ),
    'strategies' => array(
        'ViewJsonStrategy',
    ),
),
如果我加一行

throw new \Exception($translator->translate('Access denied'));

在重定向代码之后,我确实被重定向到URL
http://[servername]/error/403
,但是页面的内容不是我的自定义
403.phtml
,而是一个样式化(带有布局)404错误页面,声明“请求的URL无法通过路由匹配”

实现所需的更好方法是在
checkAcl
函数中触发
分派.error
事件,而不是尝试重定向。然后,您可以处理此事件并显示403页面

要触发事件,请执行以下操作:

if (!$this->acl->isAllowed($userRole, $controller, $privilege))
{
    $app = $e->getTarget();
    $route = $e->getRouteMatch();

    $e->setError('ACL_ACCESS_DENIED') // Pick your own value, would be better to use a const
      ->setParam('route', $route->getMatchedRouteName());
    $app->getEventManager()->trigger('dispatch.error', $e);
}
然后在onBootstrap中为
分派.错误
事件添加一个侦听器:

use Zend\Mvc\MvcEvent;
...

$eventManager->attach(MvcEvent::EVENT_DISPATCH_ERROR, <any callable>, -999);

StdResponse
的完整路径是什么?它是
Zend\Http\Response
的别名吗?同样(当我将
$event->setResult($base\u model)
替换为
$event->setResult($baseModel)
)时,在输出中我只从
布局/布局中获取HTML,而不是从
错误/403中获取HTML,即使
error/403
中的变量似乎设置正确(由
layout/layout
使用确认,例如页面标题和一个
元素),即使
layout/layout
中的行
没有更改。我已经知道如何呈现我的子视图。我是通过向
addChild
提供一个参数名来实现的,比如
$baseModel->addChild($model,'child')和echo
ing
$this->child
。我还用
StdResponse
注释掉了整个部分。不过,我会接受你的回答,即使它需要一些改变才能工作。嗨,我也是!,需要知道什么是StdResponse,哪个是它的完整路径,或者它是否是别名。。。谢谢@razor7它是Zend\Stdlib\Response的别名
$error = $event->getError();

if (empty($error) || $error != "ACL_ACCESS_DENIED") {
    return;
}

$result = $event->getResult();

if ($result instanceof StdResponse) {
    return;
}

$baseModel = new ViewModel();
$baseModel->setTemplate('layout/layout');

$model = new ViewModel();
$model->setTemplate('error/403');

$baseModel->addChild($model);
$baseModel->setTerminal(true);

$event->setViewModel($baseModel);

$response = $event->getResponse();
$response->setStatusCode(403);

$event->setResponse($response);
$event->setResult($baseModel);

return false;