0

似乎 LWP::UserAgent 总是将表单数据编码为 UTF-8,即使明确地将其编码为 ISO-8859-1,如下所示:

use Encode;
use LWP::UserAgent;
use utf8;

my $ua = LWP::UserAgent->new;
$ua->post('http://localhost:8080/', {
    text => encode("iso-8859-1", 'è'),
});

请求内容为text=%C3%A8。我怎么能è编码为%E8呢?

4

3 回答 3

2

呵呵。:-) 这与最近十几个 Perl 版本中对 Unicode 的支持不断增长以及模块\C使用的正则表达式功能有关,更准确地说,由. 从 2010 年开始阅读perl-unicode 上的这个线程(不要在正则表达式中使用 \C 转义 - 为什么不呢?)以了解背景。URIURI::Escape

为什么是URI模块?因为它是用来做表单和 URL 编码的HTTP::Request::Common

同时,我写了一个脚本来提醒自己这个问题有多么棘手,特别是因为该URI模块是一个经常使用的模块:

use 5.010;
use utf8;
# Perl and URI.pm might behave differently when you encode your script in
# Latin1 and drop the utf8 pragma.
use Encode;
use URI;
use Test::More;
use constant C3A8 => 'text=%C3%A8';
use constant   E8 => 'text=%E8';
diag "Perl $^V";
diag "URI.pm $URI::VERSION";
my $chars = 'è';
my $octets = encode 'iso-8859-1', $chars;
my $uri = URI->new('http:');

$uri->query_form( text => $chars );
is $uri->query, C3A8, C3A8;

my @exp;
given ( "$^V $URI::VERSION" ) {
        when ( 'v5.12.3 1.56' ) { @exp = (   E8, C3A8 ) }
        when ( 'v5.10.1 1.54' ) { @exp = ( C3A8, C3A8 ) }
        when ( 'v5.10.1 1.58' ) { @exp = ( C3A8, C3A8 ) }
        default                 { die 'not tested :-)' }
}

$uri->query_form( text => $octets );
is $uri->query, $exp[0], $exp[0];

utf8::upgrade $octets;
$uri->query_form( text => $octets );
is $uri->query, $exp[1], $exp[1];

done_testing;

所以我得到(在 Windows 和 Cygwin 上)是:

C:\Windows\system32 :: perl \Opt\Cygwin\tmp\uri.pl
# Perl v5.12.3
# URI.pm 1.56
ok 1 - text=%C3%A8
ok 2 - text=%E8
ok 3 - text=%C3%A8
1..3

和:

MiLu@Dago: ~/comp > perl /tmp/uri.pl
# Perl v5.10.1
# URI.pm 1.54
ok 1 - text=%C3%A8
ok 2 - text=%C3%A8
ok 3 - text=%C3%A8
1..3

更新

您可以手工制作请求正文:

use utf8;
use Encode;
use LWP::UserAgent;
my $chars = 'ölè';
my $octets = encode( 'iso-8859-1', $chars );
my $body = 'text=' .
        join '',
        map { $o = ord $_; $o < 128 ? $_ : sprintf '%%%X', $o }
        split //, $octets;
my $uri = 'http://localhost:8080/';
my $req = HTTP::Request->new( POST => $uri, [], $body );
print $req->as_string;
my $ua = LWP::UserAgent->new;
my $rsp = $ua->request( $req );
print $rsp->as_string;
于 2011-06-23T19:53:30.980 回答
1
use strict;
use warnings;
use utf8;  # Script is encoded using UTF-8.

use Encode                qw( encode );
use HTTP::Request::Common qw( POST );  # This is what ->post uses

my $req = POST('http://localhost:8080/', {
    text => encode("iso-8859-1", 'è'),
});

print($req->as_string());

POST http://localhost:8080/
Content-Length: 8
Content-Type: application/x-www-form-urlencoded

text=%E8

您是否使用传递«è» 而不是其 UTF-8 编码?如果我使用它的 UTF-8 编码,我会得到和你一样的结果。

...
my $req = POST('http://localhost:8080/', {
    text => encode("iso-8859-1", encode("UTF-8", 'è')),
});
...

POST http://localhost:8080/
Content-Length: 11
Content-Type: application/x-www-form-urlencoded

text=%C3%A8
于 2011-06-23T19:09:23.610 回答
1

对我自己的简短回答:只需将变量名(即“文本”)放在引号中,而不是将其写成裸词。

$ua->post('http://localhost:8080/', {
    'text' => encode("iso-8859-1", 'è'),
});

比率:这种奇怪的行为是由以下因素的组合引起的:

  • Perl 错误 #68812导致将 UTF-8 内部标志设置为所有裸字。这已在最新的 Perl 版本 (>= 5.12) 中得到修复;
  • URI.pm 在转换字符之前将键连接到值(即“text=è”),因此如果键设置了内部标志,则该值始终提升为 UTF-8,即使您将值作为八位字节传递也是如此。

我不认为@Lumi 指出的关于 URI.pm 使用的错误\C对这个特定问题有影响。

于 2011-06-24T14:53:09.857 回答