[英]session_write_close() doesn't work with Symfony's built-in server, and with Apache with simultaneous browser pages
关于Symfony / Php会话,以及在已经花费很长时间进行处理的控制器中打开会话时发生的锁定,我也遇到两个类似的问题。 它与session_write_close()
Php函数有关。
这是一个需要很长时间才能处理的控制器的简单示例:
<?php
// TestController.php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class TestController extends Controller
{
/**
* @Route("/test", name="test")
*/
public function testAction(Request $request)
{
// Close the session to unblock other parallel requests:
session_write_close();
$seconds_to_wait = (int) $request->query->get('time', 10);
usleep($seconds_to_wait * 1000000);
return new Response("Waited for $seconds_to_wait seconds");
}
}
为了不阻止其他请求,我在控制器的开头使用session_write_close()
。
这是一些HTML / JS前端,用于测试对此控制器的XHR请求:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8" /></head>
<body>
<button>Send requests</button>
<ul id="log"></ul>
<script type="text/javascript" src="/js/jquery-2.2.4.min.js"></script>
<script type="text/javascript">
function log(message) {
$('#log').append($('<li>').text(new Date().toTimeString() + ' : ' + message));
}
function send_requests() {
var times = [ 8, 2, 6 ]; // Send 3 requests, first one is longer than the next one
for (var i in times) {
log('A request was sent ('+times[i]+'s)');
$.ajax({
url: '/test', data: { time: times[i] },
dataType: 'text',
success: function(response) { log(response) }
});
}
}
$(function() {
$('button').click(function() { send_requests() });
});
</script>
</body>
</html>
多亏了session_write_close()
调用,当我在prod
环境中尝试此页面而不使用Symfony内置服务器(取而代之的是Apache)时,它的工作正常。 例如,上面的代码给出了预期的结果:
14:19:20 GMT+0200 (CEST) : A request was sent (8s)
14:19:20 GMT+0200 (CEST) : A request was sent (2s)
14:19:20 GMT+0200 (CEST) : A request was sent (6s)
14:19:22 GMT+0200 (CEST) : Waited for 2 seconds <-- Right, it didn't wait for the first request
14:19:26 GMT+0200 (CEST) : Waited for 6 seconds
14:19:28 GMT+0200 (CEST) : Waited for 8 seconds
但是,这是两个问题:
dev
环境中使用Symfony内置服务器时 ,它不再起作用。 在这种情况下,它的作用就好像没有调用session_write_close()
一样,进一步的请求必须等待较旧的请求完成。 这里是同一页面的输出,但具有不同的上下文: 14:10:06 GMT+0200 (CEST) : A request was sent (8s)
14:10:06 GMT+0200 (CEST) : A request was sent (2s)
14:10:06 GMT+0200 (CEST) : A request was sent (6s)
14:10:14 GMT+0200 (CEST) : Waited for 8 seconds
14:10:16 GMT+0200 (CEST) : Waited for 2 seconds <-- Oops, this request had to wait for the 1st one
14:10:22 GMT+0200 (CEST) : Waited for 6 seconds
如我所写,当我用Apache而不是内置服务器执行一些XHR请求时,它运行良好。 但是使用Apache和prod
环境也存在一个问题:
在浏览器中,当我尝试直接打开长期请求的网址时(例如: /test?time=15
),但同时在两个不同的页面中,再次发生相同的问题:我必须等待〜第二页30秒,而不是15秒。
编辑:Mathias指出了第一个问题:这是由于Php内置服务器的局限性,后者仅“旨在帮助应用程序开发”。
对于开发人员/内置服务器问题,有一个简单的答案:
Web服务器仅运行一个单线程进程,因此,如果请求被阻止,PHP应用程序将停止。 ( http://php.net/manual/zh/features.commandline.webserver.php )
因此,这种情况下的问题与会话无关,但是Web服务器不支持处理您的同时请求。
关于session_write_close()
提示:您可以在会话对象上调用save()
来保存待处理的会话数据并关闭会话(取决于您的存储, session_write_close
将在内部被调用)。 这是Symfony在返回响应之前在流程结束时所做的操作(请参阅https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpKernel/EventListener/SaveSessionListener.php )。 例:
<?php
namespace AppBundle\Controller;
// use ...
class TestController extends Controller
{
public function testAction(Request $request)
{
$request->getSession()->save();
return new Response('foo');
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.