如何将自定义事务ID传递给SOAP::Lite的日志传输函数?
解决SOAP::Lite传递事务ID到日志回调的问题
下面提供两种无需使用outputxml的方案,实现将getWords中的txn_id传递给log_transport日志函数:
方案一:利用闭包绑定事务ID
通过在getWords中创建绑定当前txn_id的闭包,动态替换SOAP对象的日志回调,实现上下文传递:
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use SOAP::Lite +trace => [ transport => \&log_transport, ]; sub log_transport { my ($in) = @_; # 原全局日志逻辑(可选保留,若不需要可注释) if (ref($in) eq "HTTP::Request") { say STDERR Dumper(ref($in), $in->content); } elsif (ref($in) eq "HTTP::Response") { say STDERR Dumper(ref($in), $in->content); } } $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME}=0; my $soap = SOAP::Lite->proxy('https://www.dataaccess.com/webservicesserver/NumberConversion.wso?op=NumberToWords'); $soap->serializer()->register_ns('http://www.dataaccess.com/webservicesserver/' ,"ns"); sub getWords { my ($number, $txn_id) = @_ ; # 保存原日志回调(若不需要保留原逻辑可省略此步骤) my $original_logger = $soap->transport->{'_hooks'}->{'trace'}->[0]; # 创建绑定txn_id的闭包作为临时日志回调 my $txn_logger = sub { my ($in) = @_; if (ref($in) eq "HTTP::Request") { # 插入日志逻辑,使用当前txn_id # INSERT INTO logs ( txn_id, request ) VALUES ( ?, ? ) say STDERR "txn_id: $txn_id, Request content: ", $in->content; } elsif (ref($in) eq "HTTP::Response") { # 更新日志逻辑,使用当前txn_id # UPDATE logs SET response = ? WHERE txn_id = ? say STDERR "txn_id: $txn_id, Response content: ", $in->content; } # 调用原日志回调(若保留原逻辑则执行) $original_logger->($in) if $original_logger; }; # 设置临时日志回调 $soap->transport->add_hook(trace => $txn_logger); my $method = SOAP::Data->name("ns:NumberToWords"); my @params = ( SOAP::Data->name("ubiNum" => $number) ); my $response = $soap->call($method => @params); # 恢复原日志回调(若复用SOAP对象则必须执行) $soap->transport->{'_hooks'}->{'trace'}->[0] = $original_logger; if (!$response->fault) { say STDOUT "NumberToWords = " . $response->result; } else { say STDERR "error: " . (defined $response->faultstring? $response->faultstring : $soap->transport->status); } } getWords(444, '123abc');
方案二:通过自定义HTTP请求头传递事务ID
在请求中添加自定义HTTP头携带txn_id,在日志回调中从请求/响应对象提取该ID:
1. 修改日志回调函数
sub log_transport { my ($in) = @_; my $txn_id; if (ref($in) eq "HTTP::Request") { # 从请求头提取txn_id $txn_id = $in->header('X-Txn-ID'); # INSERT INTO logs ( txn_id, request ) VALUES ( ?, ? ) say STDERR "txn_id: $txn_id, Request content: ", $in->content; } elsif (ref($in) eq "HTTP::Response") { # 从响应关联的请求中提取txn_id $txn_id = $in->request->header('X-Txn-ID'); # UPDATE logs SET response = ? WHERE txn_id = ? say STDERR "txn_id: $txn_id, Response content: ", $in->content; } }
2. 修改getWords函数添加请求头
sub getWords { my ($number, $txn_id) = @_ ; # 设置自定义HTTP头携带txn_id $soap->transport->http_request->header('X-Txn-ID' => $txn_id); my $method = SOAP::Data->name("ns:NumberToWords"); my @params = ( SOAP::Data->name("ubiNum" => $number) ); my $response = $soap->call($method => @params); if (!$response->fault) { say STDOUT "NumberToWords = " . $response->result; } else { say STDERR "error: " . (defined $response->faultstring? $response->faultstring : $soap->transport->status); } }
说明
- 方案二无需修改日志回调的绑定逻辑,实现更简洁,适合大多数场景
- 两种方案均避免了使用
$soap->outputxml(1)->call()的方式
内容的提问来源于stack exchange,提问作者h q
相关产品推荐
相关产品推荐

