使用服务器发送事件在 cakephp 3 中实现数据库插入进度条
Implementing Database Inserting progress bar in cakephp 3 using Server Sent Events
我有一个包含大量数据的 csv 文件。目标是将此数据导入数据库。最初文件在客户端处理,然后在客户端验证后,将其发送到服务器以进行数据库插入。
在我的服务器端,我使用 cakephp 3 框架。
我需要的是从控制器操作向客户端提供更新(即插入数据的百分比)。
我进行了研究,偶然发现了可用于该解决方案的服务器发送事件。如果我让下面的代码工作,我就能弄清楚如何将进度通知客户端。但是,当我试用示例代码时,我不断收到 readyState 等于 EventSource.CONNECTING.
的 'error' 事件
这是从 SSE 教程站点获取的示例代码,我只是尝试将其应用于 cakephp 3:
index.ctp
<button id="btnStartTheClock">start</button>
<button id="btnStopTheClock">stop</button>
<div id="result"></div>
<script type="text/javascript">
var essSupport = false, es, result;
function init() {
esSupport = (window.EventSource !== undefined);
result = document.getElementById("result");
document.getElementById("btnStartTheClock").onclick = startTheClock;
document.getElementById("btnStopTheClock").onclick = stopTheClock;
}
window.onload = init;
function startTheClock() {
if(esSupport) {
if (es === undefined) {
es = new EventSource("import-progress");
es.addEventListener('message', function (event) {
result.innerHTML += event.data + '<br/>';
});
es.addEventListener('open', function (e) {
result.innerHTML += "<span style='color:green;'>SSE open</span><br/>";
});
es.addEventListener('error', function(e) {
e = e || event, msg = '';
switch( e.target.readyState ){
// if reconnecting
case EventSource.CONNECTING:
msg = 'Reconnecting…';
break;
// if error was fatal
case EventSource.CLOSED:
msg = 'Connection failed. Will not retry.';
break;
}
result.innerHTML += '<span style="color:red;">' + msg + "</span><br>";
});
}
}
else {
result.innerHTML = "Your browser doesn't support server-sent events.";
}
}
function stopTheClock() {
if(esSupport) {
es.close();
result.innerHTML += "Clock Stopped.<br>";
}
}
</script>
SamplesController.php
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Controller\Component\RequestHandlerComponent;
use Cake\Event\Event;
class SamplesController extends AppController
{
public function initialize()
{
parent::initialize();
// $this->loadComponent('RequestHandler');
}
public function index()
{
}
public function importProgress()
{
$this->set('datetime', date("h:i:s"));
}
}
import_progress.ctp
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
echo "data: The server time is: {$datetime}\n\n";
flush();
?>
如果你愿意:
- 为了实现这个目标,我需要寻找或了解什么?
- 你能提出一个不同的解决方案吗?
旁注:
- 我是 CakePHP 新手
- 我是服务器端事件的新手
谢谢!
我会考虑使用 websockets 而不是 SSE——它似乎获得了更多的关注——然后你就可以使用例如。 Ratchet or ReactPHP.
另一件事 - 将进度保存在您的数据库中可能更容易,只需向端点发出 AJAX 请求,每隔 x 秒检查此作业的 status/progress。
例如,如果您使用 https://github.com/dereuromark/cakephp-queue - you can see an example of how to update a job's status here: https://github.com/dereuromark/cakephp-queue/tree/master/docs#updating-status
这是一个老话题:
Show progress for long running PHP script
记得从服务器端关闭循环,以防止不必要的循环。
Websocket 主要用于持续的持久连接,而不是像这样的一次性任务。没有意义 运行 websocket 无缘无故地监听循环。
我有一个包含大量数据的 csv 文件。目标是将此数据导入数据库。最初文件在客户端处理,然后在客户端验证后,将其发送到服务器以进行数据库插入。
在我的服务器端,我使用 cakephp 3 框架。
我需要的是从控制器操作向客户端提供更新(即插入数据的百分比)。
我进行了研究,偶然发现了可用于该解决方案的服务器发送事件。如果我让下面的代码工作,我就能弄清楚如何将进度通知客户端。但是,当我试用示例代码时,我不断收到 readyState 等于 EventSource.CONNECTING.
的 'error' 事件这是从 SSE 教程站点获取的示例代码,我只是尝试将其应用于 cakephp 3:
index.ctp
<button id="btnStartTheClock">start</button>
<button id="btnStopTheClock">stop</button>
<div id="result"></div>
<script type="text/javascript">
var essSupport = false, es, result;
function init() {
esSupport = (window.EventSource !== undefined);
result = document.getElementById("result");
document.getElementById("btnStartTheClock").onclick = startTheClock;
document.getElementById("btnStopTheClock").onclick = stopTheClock;
}
window.onload = init;
function startTheClock() {
if(esSupport) {
if (es === undefined) {
es = new EventSource("import-progress");
es.addEventListener('message', function (event) {
result.innerHTML += event.data + '<br/>';
});
es.addEventListener('open', function (e) {
result.innerHTML += "<span style='color:green;'>SSE open</span><br/>";
});
es.addEventListener('error', function(e) {
e = e || event, msg = '';
switch( e.target.readyState ){
// if reconnecting
case EventSource.CONNECTING:
msg = 'Reconnecting…';
break;
// if error was fatal
case EventSource.CLOSED:
msg = 'Connection failed. Will not retry.';
break;
}
result.innerHTML += '<span style="color:red;">' + msg + "</span><br>";
});
}
}
else {
result.innerHTML = "Your browser doesn't support server-sent events.";
}
}
function stopTheClock() {
if(esSupport) {
es.close();
result.innerHTML += "Clock Stopped.<br>";
}
}
</script>
SamplesController.php
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Controller\Component\RequestHandlerComponent;
use Cake\Event\Event;
class SamplesController extends AppController
{
public function initialize()
{
parent::initialize();
// $this->loadComponent('RequestHandler');
}
public function index()
{
}
public function importProgress()
{
$this->set('datetime', date("h:i:s"));
}
}
import_progress.ctp
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
echo "data: The server time is: {$datetime}\n\n";
flush();
?>
如果你愿意:
- 为了实现这个目标,我需要寻找或了解什么?
- 你能提出一个不同的解决方案吗?
旁注:
- 我是 CakePHP 新手
- 我是服务器端事件的新手
谢谢!
我会考虑使用 websockets 而不是 SSE——它似乎获得了更多的关注——然后你就可以使用例如。 Ratchet or ReactPHP.
另一件事 - 将进度保存在您的数据库中可能更容易,只需向端点发出 AJAX 请求,每隔 x 秒检查此作业的 status/progress。
例如,如果您使用 https://github.com/dereuromark/cakephp-queue - you can see an example of how to update a job's status here: https://github.com/dereuromark/cakephp-queue/tree/master/docs#updating-status
这是一个老话题:
Show progress for long running PHP script
记得从服务器端关闭循环,以防止不必要的循环。 Websocket 主要用于持续的持久连接,而不是像这样的一次性任务。没有意义 运行 websocket 无缘无故地监听循环。