Silex Route 在 before() 中短路会跳过 Route 但仍会执行 after() 事件

Silex Route Short-circuiting in before() skips the Route but still executes after() events

manual表示->before中间件可以像这样短路路由器:

$app->before(function (Request $request) {
    if (...) {
        return new RedirectResponse('/login');
    }
});

我的实现是这样的:

$app->post( '/push/{id}', function( $id, Request $request, Application $app ) {
    $app['post.data'] = $request->request->all();
})
->assert( 'id', '[a-f\d]{24}' )
->before(function( Request $request, Application $app ){
    $item = $app['mongodb.maps']->findOne([
        '_id' => new MongoId( $request->get('id') )
    ]);
    if( !$item ) {
        return new RedirectResponse( 'http://test.com', 301 );
    } else $app['mapdata'] = $item;
})
->after(function( Request $request, Response $response, Application $app ){
    if( !isset( $app['post.data'] ) ) {
        return new RedirectResponse( 'http://google.com', 301 );
    }
})
->after(function( Request $request, Response $response, Application $app ){
    if( !isset( $app['post.data'] ) ) {
        return new RedirectResponse( 'http://google.com', 301 );
    }
});

如果 assert() 成功,则 before 事件会获取必要的数据,然后将其传递到全局变量中。因为我 return 重定向它跳过路由但随后执行后续事件。在之后的事件中,我检查是否存在应在路由中创建的 post 数据,因为未执行路由会引发 post.data 键未定义的错误。我现在在那里抛出一个重定向以最终重定向。但是我必须在每个 after() 方法中都这样做,否则我会得到键未定义的错误。 (它永远不会重定向到 test.com)

这正常吗?有没有更可靠的方法来退出 at before 并跳过所有其他调用?

作为 documentation states(强调我的):

If a before middleware returns a Response object, the request handling is short-circuited (the next middlewares won't be run, nor the route callback), and the Response is passed to the after middlewares right away.

所以是的,这是正常行为。

我也没有看到一个简单的方法来做你想做的事。不考虑太多,一个选项可能是不使用默认的 after 中间件,而是扩展 Silex\Application 并创建自定义的 after 中间件来检查如果参数存在:

<?php

use Symfony\Component\HttpFoundation\RedirectResponse;
use Silex\Application as SilexApp

class MyApp extends SilexApp
{
    public function myAfter($callback, $priority = 0)
    {
        $app = $this;
        $this->on(KernelEvents::RESPONSE, function (FilterResponseEvent $event) use ($callback, $app) {
            if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
                return;
            }
            // Make sure that the callback is called when the pre conditions are met
            if (!empty($app['post.data'])) {
                $response = call_user_func($app['callback_resolver']->resolveCallback($callback), $event->getRequest(), $event->getResponse(), $app);
                if ($response instanceof Response) {
                    $event->setResponse($response);
                } elseif (null !== $response) {
                    throw new \RuntimeException('An after middleware returned an invalid response value. Must return null or an instance of Response.');
                }
            }
            else {
                $event->setResponse(new RedirectResponse('http://google.com', 301));
            }
        }, $priority);        
    }
}