You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mojolicious动态生成Tar归档文件无法打开问题求助

Tar归档文件可被识别但无法打开的问题排查与修复

我用Mojolicious实现了一个接口,允许用户下载指定目录下的所有文件为Tar归档包,部署在Caddy代理之后。虽然下载的文件被file命令识别为POSIX tar归档,但归档工具无法正常打开它。

原实现代码:

get '/admin/downloadmedia' => sub {
    my $c = shift;

    my $tar = Mojo::Tar->new;

    my $cb = $tar->files( [ glob('../files/*') ] )->create;
    warn Dumper( $tar->files );
    my $drain;
    $drain = sub {
        my $me = shift;
        return $me->finish if ( $tar->is_complete );
        my $chunk = $cb->();

        $me->write( $chunk, $drain );
    };

    $c->res->content->headers->add( 'Content-Type',        'application/tar' );
    $c->res->content->headers->add( 'Content-Disposition', 'attachment;filename=Zahaan-Bday-Media.tar' );

    $c->$drain;
};

文件识别结果:

$ file Downloads/Zahaan-Bday-Media\ \(1\).tar
Downloads/Zahaan-Bday-Media (1).tar: POSIX tar archive

问题原因

流式写入逻辑错误:当$cb->()返回undef(表示Tar内容已生成完毕)时,代码仍尝试写入空内容,破坏了Tar归档的完整性;同时$tar->is_complete的判断时机错误,应该在获取chunk后检查而非之前。

修复后的代码

get '/admin/downloadmedia' => sub {
    my $c = shift;

    my $tar = Mojo::Tar->new;
    my $cb = $tar->files( [ glob('../files/*') ] )->create;

    my $drain = sub {
        my $me = shift;
        my $chunk = $cb->();
        
        # 无更多内容则结束响应
        return $me->finish unless defined $chunk;
        
        $me->write( $chunk, $drain );
    };

    # 改用Mojolicious标准方法设置响应头,避免重复添加
    $c->res->headers->content_type('application/tar');
    $c->res->headers->content_disposition('attachment;filename=Zahaan-Bday-Media.tar');

    $c->$drain;
};

修复说明

  • 修正流式写入逻辑:先获取chunk,判断存在后再写入,无内容直接结束响应
  • 用Mojolicious内置的content_type和content_disposition方法设置响应头,更规范且避免重复添加
  • 移除了调试用的warn Dumper(如需调试可保留,生产环境建议删除)

内容的提问来源于stack exchange,提问作者Pradeep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:43:33