如何在Laravel中使用分块传输编码?

4
您好。我想知道在API响应中是否可以使用分块传输编码(CTE)?我有大量的数据存储在数据库中,需要在一个请求中将其传输给客户端。我已经阅读了很多关于CTE机制的文章,但是遗憾的是我无法找到如何实现它。
需要注意的一件重要的事情:没有分页。这应该是一个自主系统,将数据返回到客户端终点,而不是网页。
正如我所提到的,数据存储在数据库中。唯一的问题是如何将数据分割成段(块),并将它们逐个发送到一个API响应中。
谢谢。

我不太明白分块传输编码与问题有什么关系。你说的“将数据分成段”是什么意思?你在发送整个结果集时遇到了什么问题?我们具体要处理多少条记录? - Travis Britz
它可能包含10条记录,但每个记录都有一个包含100k+条目的json字段。 - Andrii H.
因此,将每个条目逐个作为块流式传输是完美的选择。 - Andrii H.
2个回答

1
在我的具体情况下,我通过使用这段代码(示例)解决了我的问题:
use Symfony\Component\HttpFoundation\StreamedResponse;

$response = new StreamedResponse();
$response->setCallback(function () {
    var_dump('Hello World');
    flush();
    sleep(2);
    var_dump('Hello World');
    flush();
});
$response->send();

0

我认为你可能对查询构建器上的块方法感兴趣。

分块结果

如果您需要处理数千条数据库记录,请考虑使用chunk方法。该方法每次检索一小块结果并将每个块馈送到闭包进行处理。该方法非常适用于编写处理数千条记录的Artisan命令。例如,让我们以每次100条记录的块来处理整个用户表:

$response = new \Symfony\Component\HttpFoundation\StreamedResponse(function() {
    $handle = fopen('php://output', 'w');

    DB::table('users')->orderBy('id')->chunk(100, function ($users) use($handle) {
        foreach ($users as $user) {
            fputs($handle, json_encode($user));
        }
    });

    fclose($handle);
});

return $response;

进一步阅读:https://laravel.com/docs/master/queries#chunking-results

分块传输编码

据我所知,如果您返回JSON响应,Laravel 默认情况下会执行此操作

更新:

我的解决方案过于复杂。我已经删除了StreamedResponse,因为实际上并不需要它。请参见下面的更新示例。

$json_response = collect();

DB::table('users')->orderBy('id')->chunk(100, function ($users) use($json_response) {
    foreach ($users as $user) {
        $json_response->push($user);
    }
});

return $json_response->toJson();

关于第一段:你误解了我的意思。我是指要分块发送数据,而不是获取数据。 - Andrii H.
关于第二段:数据仍按照通常方式传输,没有分块。因此我请您帮助我创建一个将 Eloquent 模型转换为分块结果的函数。 - Andrii H.
如果你想发送数据,那么我个人会为用户设置一个端点,在查询构建器上使用“chunk”方法——无论是在你的eloquent模型上设置还是在控制器中设置都可以——你将能够将其“分块”以便客户端管理。我真的相信你正在寻找的方法就是我展示在回答中的方法。为了更好地理解你的困境,也许你可以告诉我——如果是这样的话——为什么你不能使用上述方法。 - Linus Juhlin
我不明白第一种方法的意义。循环是为了做什么?什么都没有...那个方法只是用来分块 Eloquent 模型,而不是 API 响应。CTE 机制的作用如下(据我所知):它将数据转换为字节码,但先将每个字符串转换为换行符、数据长度和实际数据的组合。听起来很复杂(维基百科解释得更好)。但上面的方法只是将数据库记录分块。 - Andrii H.
@Nod 我添加了一个新的示例,希望这可以帮到你。你可能需要自定义头部来指示它是JSON响应,但除此之外应该没问题。 :) - Linus Juhlin
很遗憾,这样做行不通。原因如下:在最后一个例子中,您只是将条目推送到集合中并将集合作为JSON字符串返回。这根本不会改变行为。个人而言,我使用response()->json()返回结果,因此无需将数组转换为json并将其传递给响应(冗余步骤)。 - Andrii H.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接