【问题标题】:«HTTP::Message content must be bytes» error when trying to post尝试发布时出现«HTTP::Message content must be bytes»错误
【发布时间】:2010-06-01 16:19:33
【问题描述】:

我有以下代码:

...
sub setImage {
    my $self=shift;
    my $filename=shift;
    unless(-r $filename) {
        warn "File $filename not found";
        return;
    }
    my $imgn=shift;
    my $operation=&URI::Escape::uri_escape_utf8(
        (shift) ? "Удалить! (Delete)" : "Сохранить! (Store)");
    my $FH=&::File::open($filename, 0, 0);
    my $image;
    # &utf8::downgrade($image);
    sysread($FH, $image, 102400, 0);
    close $FH;
    my $imginfo=eval{&Image::Info::image_info(\$image)};
    if($@ or $imginfo->{"error"}) {
        warn "Invalid image: ".($@ || $imginfo->{"error"});
        return undef;
    }
    my $fields=[
        DIR       => $self->url("fl"),
        OPERATION => $operation,
        FILE_NAME => ".photo$imgn",
        # FILE      => [$filename],
        FILE      => [undef, "image.".$imginfo->{"file_ext"},
            # Content_Type => $imginfo->{"file_media_type"},
            # Content_Type => 'application/octet-stream',
            Content      => $image,
        ],
    ];
    my $response=&ZLR::UA::post(
        &ZLR::UA::absURL("/cgi-bin/file_manager")."",
        $fields,
        Content_Type => "form-data",
    );
    print $response->decoded_content;
}
...

当我尝试使用函数 setImage 时,它​​失败并出现错误 HTTP::Message content must be bytes at /usr/lib64/perl5/vendor_perl/5.8.8/HTTP/Request/Common.pm line 91。更糟糕的是,如果不使用我的所有代码并且升级 libwww-perl 就无法重现此错误。是什么原因造成的?

libww-perl 的版本:dev-perl/libwww-perl-5.836。 HTTP::Request 和 HTTP::Request::Common 来自 libwww-perl 包,版本:5.827 和 5.824。

追踪:

HTTP::Message content must be bytes at /usr/lib64/perl5/vendor_perl/5.8.8/HTTP/Request/Common.pm line 91
 at Carp::croak(unknown source)
 at HTTP::Message::__ANON__(/usr/lib64/perl5/vendor_perl/5.8.8/HTTP/Message.pm:16)
 at HTTP::Message::_set_content(/usr/lib64/perl5/vendor_perl/5.8.8/HTTP/Message.pm:136)
 at HTTP::Message::content(/usr/lib64/perl5/vendor_perl/5.8.8/HTTP/Message.pm:125)
 at HTTP::Request::Common::POST(/usr/lib64/perl5/vendor_perl/5.8.8/HTTP/Request/Common.pm:91)
 at LWP::UserAgent::post(/usr/lib64/perl5/vendor_perl/5.8.8/LWP/UserAgent.pm:397)
 at ZLR::UA::post(./zlrchecker.pl:71)
 at ZLR::Info::setImage(./zlrchecker.pl:1754)
 at main::main(./zlrchecker.pl:3893)
 at main::(./zlrchecker.pl:4148)

【问题讨论】:

  • 你为什么用&开头的subs调用?
  • @Ether 因为我总是以& 开头。
  • @ZyX,它不会隐式提供调用上下文的@_,如果您希望行为明确使用它foo(@_),而不是&foo
  • @ZyX:你根本不应该使用&,除非你完全理解这样做的后果并且确定你需要它(这应该是非常罕见的案例)。
  • doc perlsub, "&" 在命名子例程时不是可选的,例如当它用作defined() 或undef() 的参数时。当您想使用“&$subref()”或“&{$subref}()”结构使用子例程名称或引用进行间接子例程调用时,它也不是可选的,尽管“$subref->()”符号解决了这个问题。 “&”形式不仅使参数列表成为可选的,它还禁止对您提供的参数进行任何原型检查。这部分是出于历史原因,部分是因为如果您知道自己在做什么,就有一种方便的作弊方式。

标签: perl post httpwebrequest httprequest libwww-perl


【解决方案1】:

使用Devel::SimpleTrace 并粘贴跟踪。使用 cpan 安装模块。然后用-MDevel::SimpleTrace 运行你的程序,比如perl -MDevel::SimpleTrace ./myapp_run.pl

并粘贴HTTP::Request:CommonHTTP::MessageLWP的版本。

我猜你会在堆栈跟踪中看到这个:

这似乎是the code likely causing the error

*_utf8_downgrade = defined(&utf8::downgrade) ?
    sub {
        utf8::downgrade($_[0], 1) or
            Carp::croak("HTTP::Message content must be bytes")
    }
    :
    sub {
    };

utf8 中的文档是这样说的:

如果原始 UTF-X 序列失败 无法在原生 8 中表示 位编码。失败时死亡,或者,如果 FAIL_OK 的值为真,返回 假的。

你应该可以通过运行utf8::downgrade($http_message_content)来创建一个测试用例

【讨论】:

  • 在我的函数中 &utf8::downgrade($image) 不会导致死亡,但我仍然得到一个错误。如果我使用FILE => [$filename],我会收到此错误。
  • 对,这个错误就是问题所在。 HTTP::Message croaks 如果你有一个错误并带有它自己的错误(如上面的代码所示)——第二个参数 (1) 表示不要死只是返回失败,然后它会随着消息 "HTTP::Message 而死内容必须是字节”。
  • 问题是,如果我尝试以下单行,一切正常:perl -e 'use utf8; use LWP::UserAgent; my $response=LWP::UserAgent->new()->post("http://zhurnal.lib.ru/cgi-bin/file_manager", [DIR => "z/zyx", OPERATION => "Store", FILE_NAME => ".photo1", FILE => ["/home/zyx/a.a/\{smth\}/\{pic\}/speed.jpg"]], Content_Type => "form-data");'。如果我在我的函数中做同样的事情,它就会死掉。
  • 那么你的函数正在做一些愚蠢的事情。尝试在 HTTP::Message::_set_content(/usr/lib64/perl5/vendor_perl/5.8.8/HTTP/Message.pm:136) 的 $_[1] 转储中手动破解(或以其他方式获取 $content)。然后尝试通过utf8::downgrade() 运行该输出。
  • 在 main 包中注释掉 use encoding 'utf8'; 就可以了。不记得为什么我把它和use utf8;放在一起了。
【解决方案2】:

我发现这个问题的一个有效解决方案是在 HTTP 请求期间通过来自Text::Unidecodeunidecode() 解析我们放入 HTTP::Message 的任何文本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    相关资源
    最近更新 更多