如何在纯PHP/Laravel中配置WSA与WS-Addressing实现SOAP调用
解决VakifBank GetirDekont SOAP接口调用的WS-Addressing配置问题
问题背景
使用原生PHP SoapClient调用VakifBank的GetirDekont接口时,返回以下错误:
looks like we got no xml document or response
The requested URL was rejected. Please consult with your administrator.
但该WSDL在SoapUI中可正常调用,返回包含WS-Addressing头部的XML响应。核心原因是该接口强制要求请求携带WS-Addressing(WSA)头部信息,而PHP原生SoapClient默认不会自动生成这些头部。
纯PHP解决方案
通过自定义SOAP头部添加WSA必需字段,同时确保请求参数符合接口命名空间要求:
<?php // 接口参数 $params = [ 'user_name' => '****', 'password' => '****', 'customer_num' => '***', 'process_num' => 000 ]; // WSDL地址 $wsdl = "https://vbtestservice.vakifbank.com.tr/HesapHareketleri.OnlineEkstre/SOnlineEkstreServis.svc?singleWsdl"; // 初始化SoapClient $client = new SoapClient($wsdl, [ 'trace' => true, 'exceptions' => 0, 'soap_version' => SOAP_1_2 // 需根据WSDL确认SOAP版本,部分WCF服务要求1.2 ]); // 构建WS-Addressing头部 $wsaNs = 'http://www.w3.org/2005/08/addressing'; $action = 'Peak.Integration.ExternalInbound.Ekstre/ISOnlineEkstreServis/GetirDekont'; // 创建WSA头部元素 $actionHeader = new SoapHeader( $wsaNs, 'Action', $action, true // 必须设置mustUnderstand为true ); $messageId = new SoapHeader( $wsaNs, 'MessageID', 'urn:uuid:' . uuid_create(UUID_TYPE_RANDOM) ); $toHeader = new SoapHeader( $wsaNs, 'To', $wsdl ); // 设置SOAP头部 $client->__setSoapHeaders([$actionHeader, $messageId, $toHeader]); // 将参数包装到对应命名空间的请求节点下 $requestParams = [ 'GetirDekontRequest' => $params ]; // 调用接口 $result = $client->__soapCall('GetirDekont', [$requestParams]); // 打印请求和响应日志用于调试 echo "Request:\n" . $client->__getLastRequest() . "\n"; echo "Response:\n" . $client->__getLastResponse() . "\n"; ?>
关键说明
- 确认
soap_version匹配接口要求:多数WCF服务默认使用SOAP 1.2,需根据WSDL定义调整。 - WSA的
Action值必须与接口定义完全一致,可从SoapUI的请求中直接复制(注意是请求的Action,而非响应的)。 - 参数必须包裹在对应命名空间的请求节点下,避免因参数结构不匹配被服务端拒绝。
Laravel框架解决方案
方案1:使用Guzzle手动构造SOAP请求
通过Guzzle直接发送带WSA头部的XML请求,灵活可控:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use GuzzleHttp\Client; class VakifBankController extends Controller { public function getDekont() { $wsdl = "https://vbtestservice.vakifbank.com.tr/HesapHareketleri.OnlineEkstre/SOnlineEkstreServis.svc?singleWsdl"; $client = new Client(); // 构造符合要求的SOAP请求XML $xml = <<<XML <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"> <s:Header> <a:Action s:mustUnderstand="1">Peak.Integration.ExternalInbound.Ekstre/ISOnlineEkstreServis/GetirDekont</a:Action> <a:MessageID>urn:uuid:{$this->generateUuid()}</a:MessageID> <a:To s:mustUnderstand="1">$wsdl</a:To> </s:Header> <s:Body xmlns="Peak.Integration.ExternalInbound.Ekstre"> <GetirDekont> <user_name>****</user_name> <password>****</password> <customer_num>***</customer_num> <process_num>000</process_num> </GetirDekont> </s:Body> </s:Envelope> XML; try { $response = $client->post($wsdl, [ 'headers' => [ 'Content-Type' => 'application/soap+xml; charset=utf-8', 'SOAPAction' => 'Peak.Integration.ExternalInbound.Ekstre/ISOnlineEkstreServis/GetirDekont' ], 'body' => $xml ]); $responseBody = $response->getBody()->getContents(); // 解析XML响应 $xmlResponse = simplexml_load_string($responseBody); dd($xmlResponse); } catch (\Exception $e) { dd($e->getMessage()); } } // 生成UUID方法 private function generateUuid() { return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) ); } }
方案2:使用laravel-soap扩展
安装扩展后配置WSA头部:
- 安装扩展
composer require artisaninweb/laravel-soap
- 在
config/soap.php中添加客户端配置:
return [ 'clients' => [ 'vakifbank' => [ 'wsdl' => 'https://vbtestservice.vakifbank.com.tr/HesapHareketleri.OnlineEkstre/SOnlineEkstreServis.svc?singleWsdl', 'options' => [ 'trace' => true, 'exceptions' => false, 'soap_version' => SOAP_1_2 ] ] ] ];
- 在代码中调用接口并添加WSA头部:
<?php use Artisaninweb\SoapWrapper\SoapWrapper; class VakifBankController extends Controller { public function getDekont(SoapWrapper $soapWrapper) { $soapWrapper->add('vakifbank', function ($service) { $service->wsdl(config('soap.clients.vakifbank.wsdl')) ->options(config('soap.clients.vakifbank.options')); }); // 构建WSA头部 $wsaNs = 'http://www.w3.org/2005/08/addressing'; $action = new SoapHeader($wsaNs, 'Action', 'Peak.Integration.ExternalInbound.Ekstre/ISOnlineEkstreServis/GetirDekont', true); $messageId = new SoapHeader($wsaNs, 'MessageID', 'urn:uuid:' . $this->generateUuid()); $to = new SoapHeader($wsaNs, 'To', config('soap.clients.vakifbank.wsdl'), true); $soapWrapper->client('vakifbank')->__setSoapHeaders([$action, $messageId, $to]); $params = [ 'user_name' => '****', 'password' => '****', 'customer_num' => '***', 'process_num' => 000 ]; $response = $soapWrapper->client('vakifbank')->call('GetirDekont', [$params]); dd($response); } private function generateUuid() { return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) ); } }
调试验证技巧
- 开启
trace参数后,使用__getLastRequest()输出请求XML,与SoapUI的请求对比,确保WSA头部和参数结构完全一致。 - 检查请求的Content-Type:SOAP 1.2要求
application/soap+xml,SOAP 1.1要求text/xml。
内容的提问来源于stack exchange,提问作者Mert 2973
相关产品推荐
相关产品推荐

