Laravel 无法保持长链接

目前项目有一个应用场景,我们的项目自建了一套包管理系统,有一套可以正常运行的Artisan命令去update、require等等。我们希望能够在web端实现对命令的调用。

但是由于命令可能运行很久从而超时,即使不超时长时间无响应的加载也足以让用户失去信心。所以我们想要实现的是长连接,每次输出一部分结果。

初期遇到了Apache配置问题,已经解决,如下代码可以在Apache跑通。

<?php
    echo("<html><body>");
    foreach(range(1,10) as $i) {
        echo str_pad($i,2048," ");
        @ob_flush();
        flush();
        sleep(1);
    }

随后配合popen函数实现了对独立进程的结果实时输出。

    $fp = popen("php C:\Users\ZsgsD\Desktop\Untitled-2.php", "r");
    while($b = fgets($fp, 2048)) {
        echo(str_pad($b,2048," "));
        @ob_flush();
        flush();
    }
    pclose($fp);

独立进程内容即为:

foreach(range(1,10) as $i) {
    echo $i;
    sleep(1);
}

以上参考了大量资料,实现了长连接。但是之后无法在Laravel应用,代码如下。

    private static function executeArtisan($command)
    {
        header("Connection: Keep-alive");

        $fp = popen('"'.PHP_BINARY.'" "'.base_path('artisan').'" '.$command, "r");
        while($b = fgets($fp, 2048)) {
            echo $b."<br>";
            flush();
        }

        pclose($fp);
    }

事实上,我后续尝试直接popen上一步的独立进程,依旧无法执行,所以排除artisan问题。所使用环境是Laravel5.8+Win10+PHP7.2+Apache(本地测试环境)。查阅资料后我发现很少有相关Laravel长连接的,涉及PHP长连接的我实现前两步的时候都已经参考过。因此初步判定是Laravel的问题。可否请教各位一下?

附言 1  ·  6个月前

感谢提醒,我遇到的情况是在Laravel内的长连接就像短连接一样,比如上面例子,就是10秒后一下输出1~10。

《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
最佳答案

测试了一下,感觉应该不是 Laravel 的锅。代码如下:

// routes/api.php

Route::get('/test', function () {
    echo("<html><body>");

    foreach(range(1,10) as $i) {
        echo str_pad($i,2048," ");
        @ob_flush();
        flush();
        sleep(1);
    }
});

命令行执行:

php artisan serve

随后打开 http://localhost:8000/test与原生 PHP 输出的效果无异。

6个月前 评论
wanghan 6个月前
讨论数量: 10

之前我也遇到此问题,希望能有高手提供答案吧,或者写个单页面来提供输出

6个月前 评论
Complicated

你这个得 借助swool 来实现长连接,,Php本身不支持貌似!

6个月前 评论

无法正常运行,具体的表现是什么呢?

卡住,无法实时展示结果?

或者是直接返回响应并关闭连接?

6个月前 评论

测试了一下,感觉应该不是 Laravel 的锅。代码如下:

// routes/api.php

Route::get('/test', function () {
    echo("<html><body>");

    foreach(range(1,10) as $i) {
        echo str_pad($i,2048," ");
        @ob_flush();
        flush();
        sleep(1);
    }
});

命令行执行:

php artisan serve

随后打开 http://localhost:8000/test与原生 PHP 输出的效果无异。

6个月前 评论
wanghan 6个月前
JohnZhang

@Wi1dcard 我是无法实时返回结果,马上我试试直接artisan serve,如果OK可能就回到Apache了。

6个月前 评论
JohnZhang

@Wi1dcard 非常感谢,我发现是Apache的问题。之前单文件测试中使用apache环境正确,项目环境错误。

6个月前 评论

@JohnZhang @Wi1dcard 请问 nginx 服务器不能实现该效果吗?php artisan serve 确实可以

6个月前 评论
JohnZhang

@GitPush 理论上所有服务器软件都可以,但是需要配置,apache我配置好了,就是allow一下keepalive;nginx我没有查。

6个月前 评论
GitPush 6个月前
Complicated

你实现了吗?不借助 swool的情况下?

6个月前 评论
JohnZhang (楼主) 6个月前
Complicated (作者) 6个月前
JohnZhang (楼主) 6个月前
LOST

从另一个角度讲,任务队列的本意是用来处理一些比较耗时的逻辑,而任务执行的本身与请求的响应并不是耦合的,也就是异步处理。这个时候,你让请求者等待任务处理完成,那这就是同步处理了,那又何必使用任务队列呢?

6个月前 评论
JohnZhang (楼主) 6个月前
LOST (作者) 6个月前
Complicated 5个月前

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!