服务器发送的事件在脚本完成之前不会更新

2024-04-27

我有一个更新数据库的小脚本。目前处理时间大约需要一分钟左右,但是随着数据库的增加,时间也会增加。我想在脚本运行时向用户提供更新,以便他们知道脚本的状态并且它仍在运行。我实现了服务器端事件,虽然它有效,但在脚本完全完成之前,不会将任何更新发布到网站上。

我可以上传整个脚本文件,但以下是相关部分。

首先,在脚本开始时,我检查脚本是否从命令行运行,如果不是,我发送标头,如下所示:

$cli = (PHP_SAPI === 'cli') ? 1 : 0;
if(!$cli){
    header( 'Content-Type: text/event-stream' );
    header( 'Cache-Control: no-cache' );
}

这是我在调用时发送 sse_message 的函数

function sse_message( $type, $message, $progress=0 )
{
    $d = array("type" => $type, "msg" => $message , "progress" => $progress);
    $id = time();

    echo "id: $id" . PHP_EOL;
    echo "data: " . json_encode($d) . PHP_EOL;
    echo PHP_EOL;

    ob_flush();
    flush();
}

最后这是我的监听器的 javascript 实现:

if( typeof(EventSource) !== "undefined" ){
    source = new EventSource( "../priv3/script/prowip_process.php" );
    source.addEventListener("message", function(e)
    {
        var result = JSON.parse(e.data);

        switch(result.type){
            case "update":
                if( result.msg != "" )
                    document.getElementById("prowip_status").value += "\n[INFO]: "+result.msg;
                document.getElementById("prowip_progress").value = result.progress;
                break;

            case "success":
                document.getElementById("prowip_status").value += "\n[COMPLETED]:"+result.msg;
                document.getElementById("prowip_progress").value = 100;
                document.getElementById("button_prowip_exit").disabled = false;
                source.close();
                break;

            case "error":
                document.getElementById("prowip_status").value += "\n[ERROR]: "+result.msg;
                document.getElementById("button_prowip_exit").disabled = false;
                source.close();
                break;      
        }
    }, false);
}
else{
    document.getElementById("prowip_status").value += "\n\n[ERROR]: Your browser does not support server-sent events.  Please upgrade your browser or use a different browser for this function.  Please note this script will not work with Internet Explorer."
    document.getElementById("button_prowip_exit").disabled = false;
}

再说一遍 - 一切都很完美,除了在脚本过程中没有发生更新,然后当它完成时,所有消息和进度条都会更新。

我已经在多个浏览器、计算机等中尝试过此操作,但直到整个脚本完成后才会发生网页更新。

任何帮助或意见将不胜感激。谢谢。

已于 2015 年 4 月 3 日编辑,根据要求发布更多代码

这 3 个函数调用 sse_message 或仅调用 CLI 的 echo。

function show_error( $cli, $message )
{
    if ($cli)
        echo $message."\n";
    else
        sse_message( "error", $message );
}

function show_message( $cli, $message, $progress )
{
    if ($cli)
        echo $message."[".$progress."%]\n";
    else
        sse_message( "update", $message, $progress );
}

function show_success( $cli, $message )
{
    if ($cli)
        echo $message."[100%]\n";
    else
        sse_message( "success", $message );
}

这是主函数的一个片段,显示了如何调用这些函数:

foreach ( $projects as $number => $project ) {
            $cn = strtok($number, "." );
            $pn = strtok(".");
            $wipover = $project['wip'] - $project['wip30'] - $project['wip60'] - $project['wip90'];
            $arover = $project['ar'] - $project['ar30'] - $project['ar60'] - $project['ar90'];
            $process_counter++;
            if( $process_counter >= $check ){
                $progress+=5;
                $check += intval ( $counter / 16 );
                show_message($cli,"",$progress);
            }
            if( ($project['empty']==1) and ($project['wip']==0) and ($project['ar']==0) ){
                //Do nothing...
            }
            else{
                $write_counter++;
                $update_query = "update projects set wip='{$project['wip']}', wip30='{$project['wip30']}', wip60='{$project['wip60']}', wip90='{$project['wip90']}', wipover='$wipover', ar='{$project['ar']}', ar30='{$project['ar30']}', ar60='{$project['ar60']}', ar90='{$project['ar90']}', arover='$arover' where client_num='$cn' and new_num='$pn'";
                if( ! $db->query( $update_query ) ){
                    show_error( $cli, "ERROR - update query: [$update_query] returned error: [".$db->error."]", $progress );
                }
            }
        }

我遇到过同样的问题。原来是 Web 服务器缓存了 php 的输出。

在 PHP 中,ob_flush() 和 flash() 强制将 PHP 的输出发送到 Web 服务器,但不能强制 Web 服务器将其推送到客户端。

我的解决方案是在从 PHP 刷新之前将输出填充到 800,000 个字符。 IE:

echo "data: " . str_pad($message, 800000) . PHP_EOL . PHP_EOL;

每个返回给客户端的响应大约有 6Kb 大,所以效率不是很高,但这是我让它工作的唯一方法。

希望有帮助!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

服务器发送的事件在脚本完成之前不会更新 的相关文章

随机推荐

  • 自 2012 年以来,WinSock 注册 IO 性能是否有所下降?

    我最近使用 MS 为该 API 提供的稍微可接受的文档编写了基于 WinSock Registered IO RIO 的 UDP 接收 最终的性能非常令人失望 单套接字性能有些稳定 约为每秒 180k 数据包 使用多个 RSS 队列 即多个
  • 选择从查询中检索列名称的列

    我正在寻找一种优雅的方法来从表 A 中选择列 其中列名是从表 B 上的查询中检索的 对表 B 的查询结果 col01 表 A 有几个名为 col01 col02 col03 最终查询应该是为了结果 result from B effecti
  • 根据区域设置获取货币 ISO 4217 代码

    假设我用以下命令解析 HTTP Accept Language 标头Locale acceptFromHttp http www php net manual en locale acceptfromhttp php是否有一种简单可靠的方法
  • Java 中的字符串拆分:可变长度的前向和后向

    我想使用数字作为分隔符来破坏 Java 中的字符串 但保留数字 一些研究表明 使用 String 中的 split method 是合适的 但我不明白如何做到这一点 为了进一步解释我的问题 我将使用一个例子 Input 20 55 50 0
  • 使用 VBA 从分布生成随机数到内存

    我想从 VBA Excel 2007 中选定的分布生成随机数 我目前正在使用带有以下代码的分析工具库 Application Run ATPVBAEN XLAM Random A B C D E F Where A how many var
  • 如何在 POSIXct 中获取一天的开始

    我的一天开始于2016 03 02 00 00 00 Not 2016 03 02 00 00 01 我如何开始一天的工作POSIXct当地时间 我的困惑可能来自于 R 认为这是 2016 03 01 的结束日期这一事实 鉴于 R 使用 I
  • 如何减少基于位置的 Android 应用程序的功耗?

    如何减少应用程序的功耗 我可以使用什么代码来实现这个 有几种不同的方法可以减少尝试获取位置信息时所用的电量 Use the 最后已知位置 http developer android com reference android locati
  • HtmlAgilityPack 设置节点 InnerText

    我想用其他文本替换 HTML 标签的内部文本 我正在使用 HtmlAgilityPack我使用这段代码来提取所有文本 HtmlDocument doc new HtmlDocument doc Load some path foreach
  • Spring MVC:在表单处理操作中有多个@ModelAttribute

    上下文 我在两个实体之间有一个简单的关联 Category and Email NtoM 我正在尝试创建用于浏览和管理它们的网络界面 要浏览类别并将电子邮件添加到该类别中 我使用包含以下内容的控制器 RequestMapping带有类别 I
  • 使用线程或异步任务的位图工厂动画

    这个问题是我在这个论坛上提出的多个问题的后续问题 这些问题涉及为什么我一直在尝试的动画不起作用 简单回答一下之前的问题 我的动画作为 2 个班级的单独项目工作 但无法工作 当包含在我的包含多个类的项目中时 使用 finish 类关闭了导致我
  • 如何在 Visual Studio Code 中的事件上使用 JSDoc 自定义 EventEmitter?

    我一直致力于 Node js 项目 只是注意到 Visual Studio Code 提供了有关基本 EventEmitter 对象的信息 所以我想也应该可以为自定义提供 JSDoc 我已经尝试遵循 JSDochttp usejsdoc o
  • sql查询使用pivot动态添加会计月份

    ALTER PROCEDURE dbo sp GetDMActivityTrackerReport CoachId VARCHAR 7 Month INT FiscalYear INT AS BEGIN INSERT FiscalMonth
  • 如何计算 CNN 第一个线性层的维度

    目前 我正在使用 CNN 其中附加了一个完全连接的层 并且我正在使用尺寸为 32x32 的 3 通道图像 我想知道是否有一个一致的公式可以用来计算第一个线性层的输入尺寸和最后一个卷积 最大池层的输入 我希望能够计算第一个线性层的尺寸 仅给出
  • 错误:连接超时:连接

    我将Android Studio 1 5 1的gradle版本从1 5更改为2 10 然后单击立即同步 错误图像 https i stack imgur com E3MVE png但出现以下错误 错误 连接超时 连接 如果您使用 HTTP
  • c# UWP - 将字节数组转换为 InMemoryRandomAccessStream/IRandomAccessStream

    我在将字节数组转换为InMemoryRandomAccessStream or IRandomAccessStream在 Windows 8 中 这是我的代码 但它不起作用 internal static async Task
  • 将一个 Excel 工作表中的两列与另一工作表中的两列进行比较,如果匹配,则从另一列复制数据

    我一直在考虑使用 Excel VLOOKUP 函数来完成此任务 但我对此非常不熟悉 我需要执行以下操作 在第一张纸上 A 列和 B 列包含 3000 行名字和姓氏 我需要将其与第二张纸进行比较 第二张纸也有名字和姓氏 第三列包含电子邮件地址
  • Android studio 2.3 canary 在“SDK Manager”中缺少“Launch Standalone SDK Manager”选项

    我无意中接受了 android studio 的升级建议到 2 3 金丝雀 尽管我一直将其设置为检查开发者频道 而不是金丝雀 不知何故 它被切换了 现在 我的 SDK 管理器 窗口中不再有 启动独立 SDK 管理器 选项 我喜欢独立管理器有
  • 仅验证选定的休息端点:spring boot

    我有一个 Spring Boot Web 应用程序 暴露了一些休息端点 我想知道如何仅为选定的其余端点启用基本身份验证 假设我只想 employee id 请求进行身份验证并忽略所有其他其余端点 我正在使用以下代码 我的问题是antMatc
  • C++ 中的 Java HashSet 等效项

    我很好奇 C 中是否有类似于 Java HashSet 的东西 IE 一个快速查看的数据结构 因为我只会运行 contains e 在上面 同样 如果你能启发我如何做 contains 无论您提出什么数据结构 我都会非常感激 O 请不要发帖
  • 服务器发送的事件在脚本完成之前不会更新

    我有一个更新数据库的小脚本 目前处理时间大约需要一分钟左右 但是随着数据库的增加 时间也会增加 我想在脚本运行时向用户提供更新 以便他们知道脚本的状态并且它仍在运行 我实现了服务器端事件 虽然它有效 但在脚本完全完成之前 不会将任何更新发布