首页 > 解决方案 > WSDL如何设置独立于服务执行url的目标命名空间

问题描述

我必须在 PHP 下设置一个 SOAP 服务器并且我已经让它工作了,但是因为我需要维护与开发、阶段和生产分开的状态,所以它需要从 wsdl 中获取所有真实的 url。我搜索了很多文档,但是我得到的任何示例在 wsdl 中都有目标 url,并且我完成了以下工作 wsdl

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="https://example.com/ws/OCService/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="OCService" targetNamespace="https://example.com/ws/OCService/">
  <wsdl:types>
    <xsd:schema targetNamespace="https://example.com/ws/OCService/">
      <xsd:element name="OrderCreation">
        <xsd:complexType>
            <xsd:annotation>
               <xsd:documentation>How to use the server</xsd:documentation>
           </xsd:annotation>
           <xsd:sequence>
             <xsd:element name="name" type="xsd:string"></xsd:element>
             <xsd:element name="number" type="xsd:int"></xsd:element>
             <xsd:element name="opCode" type="xsd:string"></xsd:element>
             <xsd:element name="providerCode" type="xsd:string"></xsd:element>
             <xsd:element name="amount" type="xsd:decimal"></xsd:element>
             <xsd:element name="currency" type="xsd:string"></xsd:element>
             <xsd:element name="term" type="xsd:date"></xsd:element>
             <xsd:element name="advance" type="xsd:decimal"></xsd:element>
             <xsd:element name="repair" type="xsd:decimal"></xsd:element>
             <xsd:element name="fortnight" type="xsd:int"></xsd:element>
             <xsd:element name="items" type="tns:orderedItems"></xsd:element>
         </xsd:sequence>
     </xsd:complexType>
 </xsd:element>
 <xsd:element name="OrderCreationResponse">
    <xsd:annotation>
       <xsd:documentation>Response: Error or Success</xsd:documentation>
   </xsd:annotation>
   <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="result" type="xsd:string"/>
    </xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="Orden">
    <xsd:annotation>
       <xsd:documentation>General information</xsd:documentation>
   </xsd:annotation>
   <xsd:sequence>
    <xsd:element name="name" type="xsd:string"></xsd:element>
    <xsd:element name="number" type="xsd:int"></xsd:element>
    <xsd:element name="opCode" type="xsd:string"></xsd:element>
    <xsd:element name="providerCode" type="xsd:string"></xsd:element>
    <xsd:element name="amount" type="xsd:float"></xsd:element>
    <xsd:element name="currency" type="xsd:string"></xsd:element>
    <xsd:element name="term" type="xsd:date"></xsd:element>
    <xsd:element name="advance" type="xsd:float"></xsd:element>
    <xsd:element name="repair" type="xsd:float"></xsd:element>
    <xsd:element name="fortnight" type="xsd:int"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Item">
    <xsd:annotation>
       <xsd:documentation>Item information</xsd:documentation>
   </xsd:annotation>
   <xsd:sequence>
       <xsd:element name="itemName" type="xsd:string" />
       <xsd:element name="number" type="xsd:int" />
       <xsd:element name="unity" type="xsd:string" />
       <xsd:element name="unitPrice" type="xsd:decimal" />
       <xsd:element name="quantity" type="xsd:decimal" />
       <xsd:element name="itemAmount" type="xsd:decimal" />
       <xsd:element name="itemOrder" type="xsd:string" />
   </xsd:sequence>
</xsd:complexType>
<xsd:complexType name="orderedItems">
    <xsd:annotation>
       <xsd:documentation>Array de items que integran la OC</xsd:documentation>
   </xsd:annotation>
   <xsd:sequence>
     <xsd:element name="item" type="tns:Item" minOccurs="0" maxOccurs="unbounded"/>
 </xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="OrderCreationRequest">
    <wsdl:part element="tns:OrderCreation" name="parameters"/>
</wsdl:message>
<wsdl:message name="OrderCreationResponse">
    <wsdl:part element="tns:OrderCreationResponse" name="parameters"/>
</wsdl:message>
<wsdl:portType name="OCService">
    <wsdl:operation name="OrderCreation">
      <wsdl:input message="tns:OrderCreationRequest"/>
      <wsdl:output message="tns:OrderCreationResponse"/>
  </wsdl:operation>
</wsdl:portType>
<wsdl:binding name="OCServiceSOAP" type="tns:OCService">
 <soap:binding style="document"
    transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="OrderCreation">
        <soap:operation
           soapAction="https://example.com/ws/OCService/" />
           <wsdl:input>
               <soap:body use="literal" />
           </wsdl:input>
           <wsdl:output>
               <soap:body use="literal" />
           </wsdl:output>
       </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="OCService">
    <wsdl:documentation>Orders creation service</wsdl:documentation>
    <wsdl:port binding="tns:OCServiceSOAP" name="OCServiceSOAP">
      <soap:address location="https://example.com/ws/OCService/"/>
  </wsdl:port>
</wsdl:service>
</wsdl:definitions>

关键是这种设计虽然可行,但不能满足将执行 url 从 WSDL 表中分离出来的需要,所以当从阶段到生产时,我必须修改 wsdl,这不应该发生,因为要求是保持WSDL 不可变。

有人告诉我,您可以在 http 标头中设置 url,但我不明白这种替代方法是如何工作的。

在这一点上,我将不胜感激。提前致谢。

标签: phpweb-servicessoapwsdl

解决方案


前段时间我遇到了同样的问题。在一个开发团队中,我们讨论了可能的解决方案。一种有前途的方法是使用占位符。我假设你有一个控制器来初始化你的肥皂服务器。即使在初始化之前,您也可以检查请求 URL 是什么。基于此请求 URL,然后可以相应地解析和调整 WSDL。

让我们假设您的服务位置是一个占位符。

<wsdl:service name="OCService">
    <wsdl:documentation>Orders creation service</wsdl:documentation>
    <wsdl:port binding="tns:OCServiceSOAP" name="OCServiceSOAP">
        <soap:address location="{{PLACEHOLDER}}"/>
    </wsdl:port>
</wsdl:service>

在你的控制器中,你做这样的事情......

class SoapServerController
{
    ...
    public function initAction(): void
    {
        // check the request uri
        $requestUri = $_SERVER['REQUEST_URI'];

        switch ($requestUri) {
            case 'yadda' :
                $environment = 'staging';
                $locationUri = 'https://example.com/A';
                break;
            case 'blubb' :
                $environment = 'production';
                $locationUri = 'https://example.com/B';
                break;
            default :
                $environment = 'test';
                 $locationUri = 'https://example.com/C';
                 break;
        }

        // rewrite the wsdl
        $doc = new DOMDocument();
        $doc->loadXML('https://some.location.tld/inital.wsdl');

        $address = $doc->getElementsByTagNameNS('http://schemas.xmlsoap.org/wsdl/soap/', 'address');
        $adress->setAttribute('location', $locationUri);
        
        $filename = PATH_TO_WSDL_FOLDER . '/' . $environment . '.wsdl';
        $doc->save($filename);

        // is the wsdl get parameter set?
        if (isset($_GET['wsdl'])) {
            echo $doc->saveXML();
            exit();
        }

        // initialize the soap server
        $service = new SoapService();
        $server = new SoapServer($filename, []);
        $server->setObject($service);
        $server->handle();
    }
}

请记住,这只是未经测试的示例代码。然而,团队决定为每个环境创建一个 WSDL 文件并放弃逻辑,因为为每个请求编写一个新的 WSDL 文件将带来太多的技术债务。即使使用了缓存系统。我们选择了速度和可维护、简单的代码。我不知道你要处理多少环境。对我们来说,处理四个不同的 wsdl 文件更容易。


推荐阅读