SOAP消息头中的实体被解释为操作

时间:2018-01-11 09:56:37

标签: php web-services soap wsdl soapserver

我需要在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>

处理服务执行请求的脚本非常简单。我使用一个单独的类来处理此操作以及以下内容:

$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();
        }
    }

}

我的问题如下:

我创建了以下SOAP消息,以使用SOAPUI工具模拟对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 异常。首先,它试图找到并执行一个名为&#34; platformHeader &#34;的方法。为此,在课程中没有定义任何功能&#34; OutboundHandler &#34;。

如果我不抛出此异常,&#34; OutboundHandler&#34;的notifyDelivery方法课程将被正确执行。

因此,我的问题是:为什么SoapServer将标头识别为操作?从SOAPUI我将SOAPAction HTTP标头配置为&#34; notifyDelivery&#34;。我不明白这个操作。

如何独立访问标题数据?在变量$ params中,我只有消息正文的数据。

非常感谢你。

问候

1 个答案:

答案 0 :(得分:0)

正如您在此answer中所看到的,在&#34; OutboundHandler &#34;除了WSDL中定义的每个服务的方法之外,还应该有一个方法用于每个消息头并在那里定义访问控制逻辑。你应该创建一个名为&#34; platformHeader&#34;的方法。如果凭据不正确,则抛出 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.

    }

}