【问题标题】:Perl Mojolicious EventSource gzip outputPerl Mojolicious EventSource gzip 输出
【发布时间】:2014-11-27 02:07:46
【问题描述】:

我有一个可用的 Mojolicious 服务器,它通过 HTML5 EventSource 提供数据。 效果很好,但我希望数据以 gzip 格式编码。

通过写入发送压缩数据会在 Chrome 开发工具中产生 CONTENT_DECODING_FAILED。 将建议的方法与“hook after_render”一起使用似乎不适用于事件流。 如何使用 EventSource 和 Mojolicious 发送 gzip 编码数据?

use Mojolicious::Lite;
use Mojo::Redis;
use IO::Compress::Gzip 'gzip';

my $redis = Mojo::Redis->new;

get 'radar_events' => sub {
    my $c = shift;
    $c->render_later;
    $c->inactivity_timeout(300);
    $c->res->headers->content_type('text/event-stream');
    $c->res->headers->cache_control('no_cache');
    $c->res->headers->content_encoding('gzip');
    $c->res->headers->header( 'Access-Control-Allow-Origin' => '*' );
    my $id = Mojo::IOLoop->recurring(
        5 => sub {
            $c->delay(
                sub {
                    my $delay = shift;
                    $redis->get( 'radar', $delay->begin );
                },
                sub {
                    my ( $delay, $jstring ) = @_;
                    my $buf = "event:rupdate\ndata: ".$jstring."\n\n";
                    gzip \$jstring => \my $buf;
                    $c->write($buf);
                }
            );
        }
    );
    $c->on( finish => sub { Mojo::IOLoop->remove($id) } );
};

app->start;

【问题讨论】:

    标签: perl gzip mojolicious


    【解决方案1】:

    我认为你这样做是不可能的。 Content-Encoding 是整个正文的编码,包括event:rupdate\ndata:.... 消息。此外,每条事件消息都是一行(请参阅the specification),因此您不能以这种方式传输二进制数据(如压缩数据)。

    我不知道浏览器是否支持带有事件流的内容编码。但如果他们这样做,您将需要提供一个 gzip 流,从正文的开头开始,直到完成后才结束。由于 gzip 缓冲数据以实现更好的压缩,因此您需要在添加每个事件后显式刷新 gzip 对象。

    【讨论】:

    • 谢谢史蒂芬。我尝试对整行进行编码,但它不起作用。支持它,因为我有一个 PHP 版本的服务器,它以 gzip 格式编码并且可以工作......正如你所说,它被明确刷新。
    • 您需要在单个 gzip 流中对整个正文进行编码。单独编码每一行是不够的。
    • 我以为我做到了,但我的代码中有错误...谢谢!修改了上面的工作代码。