SOAP 消息的 header 中的实体被解释为操作
Entity in the header of a SOAP message is interpreted as an operation
我需要在 php 中实现一个在 SOAP 中接收调用的网关。
Web服务的WSDL不是很复杂。接下来我公开了相同的摘录。
<portType name="DeliveryNotification">
<operation name="notifyDelivery" parameterOrder="parameters platformHeader">
<input message="tns:notifyDelivery"/>
<output message="tns:notifyDeliveryResponse"/>
</operation>
</portType>
<binding name="DeliveryNotificationPortBinding" type="tns:DeliveryNotification">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="notifyDelivery">
<soap:operation soapAction="notifyDelivery"/>
<input>
<soap:body use="literal" parts="parameters"/>
<soap:header message="tns:notifyDelivery" part="platformHeader" use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="DeliveryNotificationService">
<port name="DeliveryNotificationPortBinding" binding="tns:DeliveryNotificationPortBinding">
<soap:address location="http://localhost:8888/soapTest/outbound-test.php"/>
</port>
</service>
处理服务执行请求的脚本非常简单。我使用单独的 class 来处理此操作和以下操作:
$server = new Gateway\Debug\DebugSoapServer(OUTBOUND_API_WSDL, array(
'soap_version' => SOAP_1_2
));
$server->setObject(new Gateway\Handlers\OutboundHandlerDecorator(new Gateway\Handlers\OutboundHandler()));
try {
$server->handle();
} catch (Exception $e) {
$server->fault('Sender', $e->getMessage());
}
OutboundHandlerDecorator 将充当验证访问的代理,然后委托给最终处理程序来处理响应。
接下来我公开它的定义:
class OutboundHandlerDecorator
{
private $decorated = null;
public function __construct(OutboundHandler $decorated)
{
$this->decorated = $decorated;
}
public function __call($method, $params)
{
global $methodCalled;
$methodCalled = $method;
if (method_exists($this->decorated, $method)) {
return call_user_func_array(
array($this->decorated, $method), $params);
} else {
throw new \BadMethodCallException();
}
}
}
我的问题如下:
我使用 SOAPUI 工具创建了以下 SOAP 消息来模拟对 notifyDelivery 服务的调用。接下来我公开结果:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://test.com/">
<soapenv:Header>
<ws:platformHeader>
<platformCredentials>
<password>myPassword</password>
<userId>myUser</userId>
</platformCredentials>
<platformFlags>
<retry>1</retry>
</platformFlags>
</ws:platformHeader>
</soapenv:Header>
<soapenv:Body>
<ws:notifyDelivery>
<simId>1234567891234567789</simId>
<simIdType>ICCID</simIdType>
</ws:notifyDelivery>
</soapenv:Body>
</soapenv:Envelope>
结果我收到一条失败的 SOAP 消息,因为抛出了 BadMethodCallException 异常。因为首先它会尝试查找并执行一个名为“platformHeader”的方法,为此在 class“OutboundHandler".
如果我不抛出这个异常,"OutboundHandler"class的notifyDelivery方法会正确执行
因此,我的问题是:为什么SoapServer 将header 识别为一个操作?在 SOAPUI 中,我将 SOAPAction HTTP header 配置为 "notifyDelivery"。这个操作我看不懂。
如何独立访问 header 数据?在变量 $ params 中我只有消息的 body 的数据。
非常感谢您。
问候
正如您在此 answer 中看到的,在“OutboundHandler”处理程序中,除了 WSDL 中定义的每个服务的方法之外,还应该有一个每个消息头的方法,并在那里定义访问控制逻辑。您应该创建一个名为 "platformHeader" 的方法,如果凭据不正确,则抛出 SoapFault 异常。目前我就这样实现。
class OutboundHandler
{
/**
* Validate User Credentials
* @param $params
*/
public function platformHeader( $params ){
if(!($params->platformCredentials->password == "myPassword" && $params->platformCredentials->userId == "myUser"))
throw new \SoapFault("1", "Incorrect user, request rejected.");
}
public function notifyDelivery($params) {
// do something.
}
}
我需要在 php 中实现一个在 SOAP 中接收调用的网关。
Web服务的WSDL不是很复杂。接下来我公开了相同的摘录。
<portType name="DeliveryNotification">
<operation name="notifyDelivery" parameterOrder="parameters platformHeader">
<input message="tns:notifyDelivery"/>
<output message="tns:notifyDeliveryResponse"/>
</operation>
</portType>
<binding name="DeliveryNotificationPortBinding" type="tns:DeliveryNotification">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="notifyDelivery">
<soap:operation soapAction="notifyDelivery"/>
<input>
<soap:body use="literal" parts="parameters"/>
<soap:header message="tns:notifyDelivery" part="platformHeader" use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="DeliveryNotificationService">
<port name="DeliveryNotificationPortBinding" binding="tns:DeliveryNotificationPortBinding">
<soap:address location="http://localhost:8888/soapTest/outbound-test.php"/>
</port>
</service>
处理服务执行请求的脚本非常简单。我使用单独的 class 来处理此操作和以下操作:
$server = new Gateway\Debug\DebugSoapServer(OUTBOUND_API_WSDL, array(
'soap_version' => SOAP_1_2
));
$server->setObject(new Gateway\Handlers\OutboundHandlerDecorator(new Gateway\Handlers\OutboundHandler()));
try {
$server->handle();
} catch (Exception $e) {
$server->fault('Sender', $e->getMessage());
}
OutboundHandlerDecorator 将充当验证访问的代理,然后委托给最终处理程序来处理响应。
接下来我公开它的定义:
class OutboundHandlerDecorator
{
private $decorated = null;
public function __construct(OutboundHandler $decorated)
{
$this->decorated = $decorated;
}
public function __call($method, $params)
{
global $methodCalled;
$methodCalled = $method;
if (method_exists($this->decorated, $method)) {
return call_user_func_array(
array($this->decorated, $method), $params);
} else {
throw new \BadMethodCallException();
}
}
}
我的问题如下:
我使用 SOAPUI 工具创建了以下 SOAP 消息来模拟对 notifyDelivery 服务的调用。接下来我公开结果:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://test.com/">
<soapenv:Header>
<ws:platformHeader>
<platformCredentials>
<password>myPassword</password>
<userId>myUser</userId>
</platformCredentials>
<platformFlags>
<retry>1</retry>
</platformFlags>
</ws:platformHeader>
</soapenv:Header>
<soapenv:Body>
<ws:notifyDelivery>
<simId>1234567891234567789</simId>
<simIdType>ICCID</simIdType>
</ws:notifyDelivery>
</soapenv:Body>
</soapenv:Envelope>
结果我收到一条失败的 SOAP 消息,因为抛出了 BadMethodCallException 异常。因为首先它会尝试查找并执行一个名为“platformHeader”的方法,为此在 class“OutboundHandler".
如果我不抛出这个异常,"OutboundHandler"class的notifyDelivery方法会正确执行
因此,我的问题是:为什么SoapServer 将header 识别为一个操作?在 SOAPUI 中,我将 SOAPAction HTTP header 配置为 "notifyDelivery"。这个操作我看不懂。
如何独立访问 header 数据?在变量 $ params 中我只有消息的 body 的数据。
非常感谢您。
问候
正如您在此 answer 中看到的,在“OutboundHandler”处理程序中,除了 WSDL 中定义的每个服务的方法之外,还应该有一个每个消息头的方法,并在那里定义访问控制逻辑。您应该创建一个名为 "platformHeader" 的方法,如果凭据不正确,则抛出 SoapFault 异常。目前我就这样实现。
class OutboundHandler
{
/**
* Validate User Credentials
* @param $params
*/
public function platformHeader( $params ){
if(!($params->platformCredentials->password == "myPassword" && $params->platformCredentials->userId == "myUser"))
throw new \SoapFault("1", "Incorrect user, request rejected.");
}
public function notifyDelivery($params) {
// do something.
}
}