我正在使用Perl模块的一部分创建一个大型CSV响应。服务器运行在Plack上,我远非专家。
目前,我正在使用此类内容发送回复:
$res->content_type('text/csv');
my $body = '';
query_data (
parameters => \%query_parameters,
callback => sub {
my $row_object = shift;
$body .= $row_object->to_csv;
},
);
$res->body($body);
return $res->finalize;
但是,query_data
函数不是一个快速函数并且检索大量记录。在那里,我只是将每一行连接到$body
,并且在处理完所有行之后,发送整个响应。
出于两个显而易见的原因,我不喜欢这个:首先,在$body
被销毁之前需要大量的RAM。其次,在该方法完成工作并实际发送带有$res->body($body)
的响应之前,用户看不到任何响应活动。
我试图找到这个in the documentation的答案而没有找到我需要的东西。
我也试过在我的回调部分调用$res->body($row_object->to_csv)
,但似乎最终只发送了我对$res->body
的最后一次调用,覆盖了之前的所有调用。
有没有办法发送Plack响应来刷新每一行的内容,这样用户就可以在收集数据时实时接收内容,而不必将所有数据累积到可靠的数据中?
提前感谢任何评论!
答案 0 :(得分:2)
您不能使用Plack::Response,因为该类用于表示完整的响应,并且您一次也不会在内存中完成响应。您尝试做的事情称为流媒体,PSGI supports it即使Plack :: Response没有。
以下是您如何实施它(根据您的示例代码改编):
my $env = shift;
if (!$env->{'psgi.streaming'}) {
# do something else...
}
# Immediately start the response and stream the content.
return sub {
my $responder = shift;
my $writer = $responder->([200, ['Content-Type' => 'text/csv']]);
query_data(
parameters => \%query_parameters,
callback => sub {
my $row_object = shift;
$writer->write($row_object->to_csv);
# TODO: Need to call $writer->close() when there is no more data.
},
);
};
关于此代码的一些有趣的事情:
Plack::Response
,而不是返回sub
个对象。稍后将调用此子例程以获得实际响应。 PSGI支持这一点,以允许所谓的'#34;延迟"响应。coderef
(在本例中为$responder
),应该被调用并传递真实的响应。如果真实的反应不包括"身体" (即通常是arrayref
的第3个元素),然后$responder
将返回一个我们可以写入主体的对象。 PSGI支持此功能以允许流式传输响应。$writer
对象有两种方法write
和close
,它们的名称与其名称完全相同。别忘了拨打close
方法来完成回复;上面的代码没有显示这个,因为它应该如何调用取决于query_data
和其他代码的工作方式。$env->{'psgi.streaming'}
以确保您的确有。{/ li>
答案 1 :(得分:-1)
Plack是中间件。您是否正在使用Web应用程序框架,如Mojolicious或Dancer2,或者下面的Apache或Starman服务器?这会影响缓冲的工作方式。
上面的链接显示了Plack的作者的一个例子: https://metacpan.org/source/MIYAGAWA/Plack-1.0037/eg/dot-psgi/echo-stream-sync.psgi
或者你可以在Plack和Starman或Apache上使用Dancer2轻松完成: https://metacpan.org/pod/distribution/Dancer2/lib/Dancer2/Manual.pod#Delayed-responses-Async-Streaming
问候,彼得
答案 2 :(得分:-2)
一些阅读材料:)
请复制/粘贴/改编并报告回来