在Plack中发送无缓冲的响应

时间:2015-07-28 00:24:59

标签: perl uwsgi plack psgi

我正在使用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响应来刷新每一行的内容,这样用户就可以在收集数据时实时接收内容,而不必将所有数据累积到可靠的数据中?

提前感谢任何评论!

3 个答案:

答案 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对象有两种方法writeclose,它们的名称与其名称完全相同。别忘了拨打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)