【问题标题】:How to convince SOAP::Lite to return UTF-8 data in responses as UTF-8?如何说服 SOAP::Lite 在响应中以 UTF-8 形式返回 UTF-8 数据?
【发布时间】:2012-03-11 01:05:58
【问题描述】:

我正在尝试使用 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 在没有猴子补丁的情况下通过?

【问题讨论】:

  • 你考虑过 XML::Compile 吗?这是一段复杂的代码,但作者一丝不苟,以求正确支持。从我认识的使用过它的人那里,一旦你弄明白它对这些东西的效果会更好。我自己没有这方面的经验。
  • 上次我看它时,我一开始不明白如何使用它。我认为我缺乏所需的领域知识(编写 XSD 等)。

标签: perl soap utf-8


【解决方案1】:

我刚刚遇到了同样的问题,发现上面的讨论很有用。正如您在 OP 中所说,问题在于数据以 base64 编码并且 is_utf8 标志丢失。序列化程序中发生的事情将任何带有非 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 标志打开,则将其视为“普通”字符串。

【讨论】:

    【解决方案2】:

    使用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;
    

    【讨论】:

    • 请注意我所说的“复杂数据结构”。为了保持较低的理解工作量,测试是最小的,但请想象它是一个四维散列,转储到 20kbyte 左右。 :)
    • 我可以浮动它。我不能完全控制 SOAP 服务器,但我认为他会接受建议。谢谢你的想法。
    • SOAP 最好通过编码为 JSON 并通过网络发送。
    猜你喜欢
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 2019-11-22
    • 2011-09-07
    • 2014-10-08
    • 2012-11-08
    • 1970-01-01
    相关资源
    最近更新 更多