我对kernel.terminate
的理解是在响应返回给客户端后触发。
在我的测试中,情况似乎并非如此。如果我在内核上调用的函数中加入一个sleep(10)
,终止。浏览器也等待10秒。处理似乎在发送响应之前就已经发生了。
我有以下配置:
calendar:
class: AcmeCalendarBundleServiceCalendarService
arguments: [ @odm.document_manager, @logger, @security.context, @event_dispatcher ]
tags:
- { name: kernel.event_subscriber }
我的订阅者类:
class CalendarService implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
'kernel.terminate' => 'onKernelTerminate'
);
}
public function onKernelTerminate()
{
sleep(10);
echo "hello";
}
}
这似乎与Symfony没有发送Content-Length
标头有关。如果生成了,响应就会正确返回。
// app_dev.php
...
$kernel = new AppKernel('dev', true);
$kernel->loadClassCache();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
// --- START EDITS ---
$size = strlen($response->getContent());
$response->headers->set('Content-Length', $size);
$response->headers->set('Connection', 'close');
// ---- END EDITS ----
$response->send();
$kernel->terminate($request, $response);
这个问题原来是非常具体的我的设置(Nginx, PHP-FCGI, Symfony)。
有几个问题导致了这个问题:
- Symfony不包含
Content-Length
或Connection: close
头 PHP-FCGI不支持
fastcgi_finish_request
函数Nginx缓冲PHP-FCGI的响应,因为Gzip在解决方案是从PHP-FCGI切换到PHP-FPM以获得对fastcgi_finish_request
的支持。Symfony在执行内核终止逻辑之前会在内部调用这个函数,从而最终关闭连接。
另一个解决这个问题的方法是在Nginx上关闭Gzip,但这对我来说不是一个真正的选择。