У меня есть действие в контроллере Symfony2, который отправляет ответ клиенту (как подробно Вот). После того, как функция отправляет ответ, у меня есть подписчик на событие, который прослушивает событие onkernelTerminate так как я буду выполнять тяжелую работу после того, как ответ будет отправлен клиенту.
Кажется, что все работает нормально для той части, которая выполняет тяжелую работу, за исключением того, что в коде есть строка, ссылающаяся на службу, которая использует сессия, который нужен для хранения токенов и связи с внешним API.
Ошибка, конечно: ошибка сеанса, так как заголовки уже отправлены.
Есть ли способ начать сеанс, даже если заголовки были отправлены? Или как лучше подходить к решению этой проблемы?
Я решил эту проблему, получив сессию из входящего запроса и сохранив ее в локальной переменной в моем контроллере действий, а затем убедился, что сессия активирована или запущена:
use Symfony\Component\HttpFoundation\Request;
public function myFunctionAction(Request $request) {
$session = $request->getSession();
$session->start();
Далее я сразу отправил ответ и заголовки клиенту:
ob_start();
$response = new Response('Status: OK', 200);
echo $response; // send the response
header('Connection: close');
header('Content-Length: ' . ob_get_length());
ob_end_flush();
if (ob_get_level() > 0) {
ob_flush();
}
flush();
Затем код продолжает выполнять тяжелую работу как обычно. Однако ключом к решению этой проблемы было убедиться, что служба, использующая сеанс, предоставляет возможность другим пользователям, которые будут ссылаться на нее, сохранять или не сохранять сеанс в службе. Если сеанс будет сохранен, он больше не будет активным и будет закрыт, а после закрытия вы не сможете запустить его снова, поскольку заголовки уже отправлены. Однако клиентский код, который ссылается на службу, должен, в конце концов, сохранить и закрыть сеанс.
Я в конечном итоге не слушал событие kernel.terminate поскольку в моем случае в этом не было необходимости.
Других решений пока нет …