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);
}
}
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);
}
}