2011-06-23 65 views
0

看來,LWP :: UserAgent的總是編碼形式的數據爲UTF-8,即使明確地對其進行編碼爲ISO-8859-1如下:如何使用LWP :: UserAgent強制使用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而不是?

+0

您是如何確定請求內容的?網絡嗅探器肯定說'text =%E8':http://i.stack.imgur.com/rM3xS.png – daxim

+0

有趣。我在端口8080上運行'nc',並得到'text =%C3%A8'。規格:MacOS X 10.6,perl v5.10.0,libwww-perl/5.837。 – Alessandro

回答

1

簡短的回答自己:只是把變量名(即「text」)用引號括起來,而不是將其寫成裸詞。

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

比率:此怪異的行爲是由下列因素引起的組合:

  • Perl bug #68812引起UTF-8內部標誌被設置爲全裸字。這在最新的Perl版本(> = 5.12)中得到修復;
  • URI.pm在轉換字符之前將鍵連接到值(即「text =è」),因此即使您將該值作爲octects傳遞,如果該鍵具有設置的內部標誌,該值也會始終提升爲UTF-8。

我不認爲@Lumi關於URI.pm使用\C指出的錯誤對此特定問題有影響。

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 
2

呵呵。 :-)這與Perl的最新版本中對Unicode的逐步增長的支持以及由URI module使用的正則表達式\C(更確切地說,是URI::Escape)有關。閱讀this thread on perl-unicode from 2010 (Don't use the \C escape in regexes - Why not?)瞭解背景。

爲什麼URI模塊?因爲它被用來做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 

和:

[email protected]: ~/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; 
+0

好,Lumi。這是醜陋醜陋的東西。將URI.pm升級到1.58並未解決問題;似乎我需要Perl 5.12來開箱即用。所以,回到我的問題,是手動構建'HTTP :: Request'是唯一實現'%E8'的便攜式方法? – Alessandro

+0

我不知道,但我會追求這條路,因爲它很容易。我更新了我的答案以包含代碼。 – Lumi

相關問題