【问题标题】:Event Source -> Server returns event stream in bulk rather then returning in chunk事件源 -> 服务器批量返回事件流,而不是块返回
【发布时间】:2015-02-19 13:31:18
【问题描述】:

我有一个 php 脚本,可以从带有验证的 csv 文件中导入大数据。
为此,我需要向用户显示进度。我为此使用了事件流。
当我回显某些内容时,我希望将其一一传输到客户端,而不是服务器批量发送整个输出。
我已经玩过 ob_start()、ob_implicit_flush() 和 ob_flush(),但是它们没有用。
我的脚本在另一台服务器上运行良好。 下面给出服务器配置:

代码未按预期响应的服务器配置,即

操作系统:Linux
PHP 版本 5.4.36-0+deb7u3
服务器 API:CGI/FastCGI
内存限制:128M
output_buffering:没有值

正如我所说,代码在另一台具有几乎相同配置的服务器上正常运行,即

操作系统:Linux
PHP 版本 5.4.37
服务器 API:CGI/FastCGI
内存限制:256MB
output_buffering:没有值

下面是我发送事件的示例代码:

<?php
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Access-Control-Allow-Origin: *");

$lastEventId = floatval(isset($_SERVER["HTTP_LAST_EVENT_ID"]) ? $_SERVER["HTTP_LAST_EVENT_ID"] : 0);
if ($lastEventId == 0) {
    $lastEventId = floatval(isset($_GET["lastEventId"]) ? $_GET["lastEventId"] : 0);
}

echo ":" . str_repeat(" ", 2048) . "\n"; // 2 kB padding for IE
echo "retry: 2000\n";

// event-stream
$i = $lastEventId;

while ($i <= 100) {
    if($i==100){
        echo "data: stop\n";
        ob_flush();
        flush();
        break;
    } else {
        echo "id: " . $i . "\n";
        echo "data: " . $i . ";\n\n";
        ob_flush();
        flush();
        sleep(1);
    }
    $i++;
}
?>

下面是我需要回复的客户页面:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>EventSource example</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <script src="../jquery/eventsource.js"></script>
    <script>
        var es = new EventSource("events.php");
        var listener = function(event) {
            console.log(event.data);
            var type = event.type;
            if (event.data == 'stop') {
                es.close();
            } else {
                var div = document.createElement("div");
                div.appendChild(document.createTextNode(type + ": " + (type === "message" ? event.data : es.url)));
                document.body.appendChild(div);
            }
        };
        var errlistener = function(event) {
            es.close();
        }
        es.addEventListener("open", listener);
        es.addEventListener("message", listener);
        es.addEventListener("error", errlistener);
    </script>
</head>

<body>
</body>

</html>

【问题讨论】:

  • 你的意思是你的实时http strimming正在其他服务器上工作????
  • 是的,它正在另一台服务器上工作......但不是在新的服务器上

标签: javascript php linux html event-stream


【解决方案1】:

将卡住的数据返回到浏览器的最佳方法是使用 Web Sockets 让客户端打开一个到文件阅读器的套接字,然后您可以毫无问题地将数据分块到浏览器。

完成后,您可以关闭套接字。

一个很好的网络套接字教程 http://www.phpbuilder.com/articles/application-architecture/optimization/creating-real-time-applications-with-php-and-websockets.html

使用这种方法,如果你想实现验证,那么服务器不仅可以发送块,它还会根据 javascript 的请求发送块

所以您的客户可以说我需要块 5,而您的服务器实现类似

$requestedChunk = 5; // this would be set by the javascript sending the request
$chunkSize = 256; // this would be your chunk size;

$readPossition = $requestedChunk * $chunkSize;

链接不再有效,因此这里是基于 Ratchet 构建的链接:https://blog.samuelattard.com/the-tutorial-for-php-websockets-that-i-wish-had-existed/

【讨论】:

  • 链接页面为 404。
  • 它实际上是一个 403,只是显示为 404 查看您被定向到的地址,但使用谷歌“php WebSocket 服务器示例”,您会发现很多
【解决方案2】:

我遇到了类似的问题。事件流在使用 Apache 2.0 处理程序的服务器上按预期工作(返回块),但在使用 FastCGI 的服务器上却没有(批量返回)。我认为 FastCGI 中的某些东西是罪魁祸首,因此试图通过切换到 CGI 来解决问题。现在事件流按预期工作。

无论是使用 CGI 还是 FastCGI,服务器 API 都显示为 CGI/FastCGI,所以我假设它为您工作的服务器正在运行 CGI,而它不为您工作的服务器正在运行 FastCGI。尝试将非工作服务器更改为 CGI。

至于为什么它在 FastCGI 中不起作用我不完全确定,但除非这是必要的要求并且 CGI 是不可能的,否则上述解决方案应该起作用。

【讨论】:

  • 不只是 FastCGI / 甚至 mod_php 都有这个问题
【解决方案3】:

许多事情可以防止分块响应,例如但不限于;

  • 网络服务器上的代理或任何其他缓冲机制
  • 当“输出缓冲”在 php.ini 中“打开”时(您应该明确将其设置为关闭)
  • 在 Web 服务器上启用 gzip 时

你应该首先检查这些。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-05
    • 1970-01-01
    • 2019-02-20
    • 2021-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多