问题描述
|
似乎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\",\'è\'),});
请求内容为“ 1”。如何将è
编码为%E8
?
解决方法
呵呵。 :-)这与最近十几个Perl版本中对Unicode的逐渐增长的支持以及
URI
模块使用的正则表达式功能\\C
(更确切地说,URI::Escape
)有关。从2010年开始在perl-unicode上阅读此线程(不要在正则表达式中使用\\ C转义-为什么不这样做?)以了解背景知识。
为什么选择“ 5”模块?因为它被用来做HTTP::Request::Common
的形式和URL编码。
同时,这是我写的一个脚本,用以提醒自己这个问题的技巧,尤其是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;
, 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/\',encode(\"UTF-8\",\'è\')),});
...
给
POST http://localhost:8080/
Content-Length: 11
Content-Type: application/x-www-form-urlencoded
text=%C3%A8
, 对自己的简短回答:只需将变量名(即\“ text \”)放在引号中,而不是将其写为裸字。
$ua->post(\'http://localhost:8080/\',{
\'text\' => encode(\"iso-8859-1\",});
比率:这种怪异的行为是由以下因素共同导致的:
Perl错误#68812导致UTF-8内部标志被设置为所有裸字。这已在最新的Perl版本(> = 5.12)中修复;
URI.pm在转换字符之前将键连接到值(即\“ text =è\”),因此即使键设置了内部标志,即使将值作为八进制传递,该值也始终提升为UTF-8。
我不认为@Lumi使用\\C
指出的有关URI.pm的错误对这个特定问题没有影响。