Как форсировать кодировку ISO-8859-1 для данных формы, используя LWP :: UserAgent? - PullRequest
0 голосов
/ 23 июня 2011

Кажется, что 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?

Ответы [ 3 ]

2 голосов
/ 23 июня 2011

Хех. :-) Это связано с возрастающей поддержкой Юникода в последних дюжинах выпусков Perl и функцией регулярного выражения \C, используемой модулем URI , если быть более точным, URI::Escape. Прочитайте эту тему по perl-unicode с 2010 года (не используйте экранирование \ C в регулярных выражениях - почему бы и нет?) , чтобы понять фон.

Почему модуль 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

UPDATE

Вы можете вручную запросить тело запроса:

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;
1 голос
/ 24 июня 2011

Краткий ответ для себя: просто поместите имя переменной (то есть "текст") в кавычки вместо того, чтобы писать ее как голое слово.

$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, повлияет на этоконкретная проблема.

1 голос
/ 23 июня 2011
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
...