1

我正在开发一个使用 REST API 后端的应用程序。这个 API 有一个登录步骤,它创建一个用于所有后续 API 请求的令牌。我将此令牌存储在身份验证存储中,并且我有一个事件挂钩来检查用户是否已登录,如果没有,则呈现登录页面:

$eventManager->attach(MvcEvent::EVENT_ROUTE, function($e) use ($view, $auth) {
    $match = $e->getRouteMatch();

    // No route match, this is a 404
    if (!$match instanceof RouteMatch) {
        return;
    }

    // Route is whitelisted
    $matchedRoute = $match->getMatchedRouteName();
    if (in_array($matchedRoute, array('login'))) {
        return;
    }

    // if they're logged in, all is good
    if ($auth->hasIdentity()) {
        return true;
    }

    [render login form and return response object]
}, -100);

这很好用。

API 有时还会以我无法轻松预测的方式使登录令牌过期,这意味着所有 API 调用都将返回“会话过期”类型错误。在我可以挂钩的 API 调用之后,我编写了一个事件触发器。我想检查这些“会话过期”响应,并以与上面相同的方式呈现登录页面:

$events->attach('Api', 'call', function ($e) {
    $api = $e->getTarget();
    $params = $e->getParams();

    $result = $params['apiResult'];

    if ([result is a session expired response]) {
        // what can I do here?
    }

}, 999);

但由于这不是 MVC 事件,即使我可以在这里访问响应对象,返回它也不会做任何事情。在非 MVC 事件中中断应用程序流的最佳方法是什么?

4

1 回答 1

1

我不确定,但我假设您的 API 事件确实发生在专用EventManager实例中(因此您的 API 可能是 的实现EventManagerAwareInterface)而不是 MVC 事件(这是您从实例中获取的Zend\Mvc\Application实例)。

如果是这种情况,您可以同时注入主APIEventManager和API 内部,然后从侦听MvcEvent器中短路 MVC 循环。call

即假设您的依赖项位于getter$mvcEvent$mvcEventManager属性中,这就是您侦听call事件的方式:

$events->attach('call', function($e) {
    $api = $e->getTarget();
    $params = $e->getParams();

    $result = $params['apiResult'];

    if ([result is a session expired response]) {
        $mvcEvent = $api->getMvcEvent();
        $mvcEvent->setError('api error');
        $mvcEvent->setParam('exception', new \Exception('Session expired'));
        $api->getMvcEventManager()->trigger('dispatch.error', $mvcEvent);
    }

}, 999);

肯定有更好的方法可以做到这一点,选择最好的将取决于您的 API 类的体系结构。

您可以使用Zend\EventManager\ResponseCollection触发器返回,而不是使用侦听器内的 MVC 事件;即使发生某些错误,这也将使您的 API 事件循环继续。这实际上就是在方法Zend\Mvc\Application中使用它自己的事件管理器的run()方式,所以你可以看看这个例子。

于 2013-10-30T15:49:59.413 回答