我正在尝试使用SOAP :: Lite在复杂的数据结构中传输UTF-8字符串。但事实证明,SOAP::Lite quietly converts all UTF-8 strings into base-64-encoded octets。问题在于反序列化does not revert the conversion并且仅a straight base64 decode。
这让我对如何确保用户从SOAP :: Lite响应中获取UTF-8数据感到困惑。走在树上并在所有字符串上运行decode_utf8
似乎很浪费。
有什么建议吗?
编辑:简而言之,如何在没有猴子修补的情况下让this test通过?
答案 0 :(得分:2)
我遇到了同样的问题,发现上面的讨论很有用。正如你在OP中所说,问题是数据是用base64编码的,而is_utf8标志是丢失的。 serlializer中发生的事情将任何带有非ascii字符的字符串视为二进制。我通过如下调整序列化器来实现我想要的。它可能有奇怪的后果,但它适用于我的情况..
use strictures;
use Test::More;
use SOAP::Lite;
use utf8;
use Data::Dumper;
my $data = "mü\x{2013}";
my $ser = SOAP::Serializer->new;
$ser->typelookup->{trick_into_ignoring} = [9, \&utf8::is_utf8 ,'as_utf8_string'];
my $xml = $ser->envelope( freeform => $data );
my ( $cycled ) = values %{ SOAP::Deserializer->deserialize( $xml )->body };
is( length( $data ), length( $cycled ), "UTF-8 string is the same after serializing" );
done_testing;
sub check_utf8 {
my ($val) = @_;
return utf8::is_utf8($val);
}
package SOAP::Serializer;
sub as_utf8_string {
my $self = shift;
my($value, $name, $type, $attr) = @_;
return $self->as_string($value, $name, $type, $attr);
}
1;
9表示在检查非ascii字符之前执行utf8检查。如果utf8标志打开,则将其视为“普通”字符串。
答案 1 :(得分:0)
使用is_utf8
(第278行)是邪恶的。因为我们不能正确地信任SOAP :: Lite和编码字符数据(公平地说,这个代码可能是在社区中有关如何进行这种特殊类型的字符串处理之前编写的),我们只给它八位字节数据因此必须自己处理编码/解码。选择一个编码,在将数据传递给S :: L之前应用它,在接收数据后将其反转。
use utf8;
use strictures;
use Encode qw(decode encode);
use SOAP::Lite qw();
use Test::More;
my $original = 'mü';
my $xml = SOAP::Serializer->envelope(
freeform => encode('UTF-8', $original, Encode::FB_CROAK | Encode::LEAVE_SRC)
);
my ($roundtrip) = map {
decode('UTF-8', $_, Encode::FB_CROAK | Encode::LEAVE_SRC)
} values %{SOAP::Deserializer->deserialize($xml)->body};
is(length($original), length($roundtrip),
'Perl character string round-trips without changing length');
done_testing;