【问题标题】:How can I built a soap server from WSDL file?如何从 WSDL 文件构建一个肥皂服务器?
【发布时间】:2021-02-19 20:10:55
【问题描述】:

我正在尝试从 WSDL 文件创建一个肥皂服务器。我正在使用 Python 3 和 Spyne 来生成它。 该服务器需要具体,因为客户端已经存在。 我需要我的 WSDL 请求如下所示

   <soapenv:Body>
      <pus:receiveEvents>
         <!--Optional:-->
         <eventQueryResult>
            <!--Optional:-->
            <queryId>?</queryId>
            <!--Optional:-->
            <queryStatus>?</queryStatus>
            <!--Zero or more repetitions:-->
            <events>
               <!--Optional:-->
               <eid>?</eid>
               <!--Optional:-->
               <eventMessage>?</eventMessage>
               <!--Optional:-->
               <eventSeverity>?</eventSeverity>
               <!--Optional:-->
               <eventTime>?</eventTime>
               <!--Optional:-->
               <eventTypeName>?</eventTypeName>
               <!--Optional:-->
               <meterId>?</meterId>
            </events>
            <subscriptionId>?</subscriptionId>
         </eventQueryResult>
      </pus:receiveEvents>
   </soapenv:Body>

但是,这是我的 WSDL 请求:

   <soapenv:Body>
      <pus:receiveEvents>
         <!--Optional:-->
         <pus:eventQueryResult>
            <!--Optional:-->
            <pus:queryId>?</pus:queryId>
            <!--Optional:-->
            <pus:queryStatus>?</pus:queryStatus>
         </pus:eventQueryResult>
         <!--Optional:-->
         <pus:events>
            <!--Optional:-->
            <pus:eid>?</pus:eid>
            <!--Optional:-->
            <pus:eventMessage>?</pus:eventMessage>
            <!--Optional:-->
            <pus:eventSeverity>?</pus:eventSeverity>
            <!--Optional:-->
            <pus:eventTime>?</pus:eventTime>
            <!--Optional:-->
            <pus:eventTypeName>?</pus:eventTypeName>
            <!--Optional:-->
            <pus:meterId>?</pus:meterId>
         </pus:events>
         <pus:subscriptionId>
            <!--Optional:-->
            <pus:subscriptionId>?</pus:subscriptionId>
         </pus:subscriptionId>
      </pus:receiveEvents>
   </soapenv:Body>

这是我写的代码

    class eventQueryResult(ComplexModel):
    __namespace__ = 'http://pushevent.nbapi.cgms.cisco.com/'

    queryId = String
    queryStatus = String

class events(ComplexModel):
    __namespace__ = 'http://pushevent.nbapi.cgms.cisco.com/'   

    eid = String
    eventMessage = String 
    eventSeverity = String
    eventTime = Long
    eventTypeName = String
    meterId = String

class subscriptionId(ComplexModel):
    __namespace__ = 'http://pushevent.nbapi.cgms.cisco.com/'

    subscriptionId = Long

class EventPushService(ServiceBase):
    __tns__ = 'http://pushevent.nbapi.cgms.cisco.com/'
    __wsdl__ = 'http://schemas.xmlsoap.org/wsdl/'

    @rpc(eventQueryResult.customize(min_occurs=0), events.customize(min_occurs=0), subscriptionId.customize(min_occurs=1,nillable = True), _returns=ResponseData)
    def receiveEvents(ctx, eventQueryResult, events, subscriptionId):
        eid = events.eid

        return print(eid)

我需要 eventQueryResult 包含事件,但我不知道如何。 Spyne 的文档对此没有帮助。

感谢您的cmets

【问题讨论】:

    标签: python python-3.x soap wsdl spyne


    【解决方案1】:

    这里有一些事情要做。代码很不完整,所以做了一些假设。这与 spyne 示例应用非常接近,与您发布的代码 sn-ps 可以确定的内容相匹配。

    当您创建类来为您的数据建模时,您希望eventQueryResult 包含事件。数组是文档here。该代码看起来更像:

    class events(ComplexModel):
        eid = String
        eventMessage = String
        eventSeverity = String
        eventTime = Long
        eventTypeName = String
        meterId = String
    
    class eventQueryResult(ComplexModel):
        queryId = String
        queryStatus = String
        events = Array(events)
    

    当您指定 RPC 时,函数的名称是 soapAction,首先是客户端将发送给您的对象的模型。在这里,整个有效载荷被建模为一个对象。 Bare 意味着负载不会被包装在数组中。根据您的客户,这可能需要更改。

        @rpc(eventQueryResult, _body_style='bare', _returns=someResponse)
    

    someResponse 是您要发送回客户端的响应的模型。我真的不知道你想要什么,一系列被接受的事件怎么样?整个脚本如下所示:

    import logging
    from spyne import Application, rpc, ServiceBase, \
        String, Long
    from spyne.protocol.soap import Soap11
    from spyne.server.wsgi import WsgiApplication
    from spyne.model.complex import ComplexModel, Array
    
    logging.basicConfig(level="WARNING")
    
    class event(ComplexModel):
        eid = String
        eventMessage = String
        eventSeverity = String
        eventTime = Long
        eventTypeName = String
        meterId = String
    
    class eventQueryResult(ComplexModel):
        queryId = String
        queryStatus = String
        events = Array(event)
    
    class someResponse(ComplexModel):
        eventIds = Array(String)
    
    class EventPushService(ServiceBase):
        @rpc(eventQueryResult, _body_style='bare', _returns=someResponse)
        def receiveEvents(ctx, req):
            print(req)
    
            return someResponse(eventIds = [ i.eid for i in req.events ] )
    
    application = Application([EventPushService],
        tns='http://pushevent.nbapi.cgms.cisco.com/',
        in_protocol=Soap11(validator='lxml'),
        out_protocol=Soap11()
    )
    
    if __name__ == '__main__':
        # You can use any Wsgi server. Here, we chose
        # Python's built-in wsgi server but you're not
        # supposed to use it in production.
    
        from wsgiref.simple_server import make_server
        wsgi_app = WsgiApplication(application)
        server = make_server('0.0.0.0', 80, wsgi_app)
        server.serve_forever()
    
    

    我正在使用看起来像这样的有效负载进行测试

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://pushevent.nbapi.cgms.cisco.com/">
      <soapenv:Header/>
      <soapenv:Body>
        <tns:receiveEvents>
          <tns:queryId>100</tns:queryId>
          <tns:queryStatus>Success</tns:queryStatus>
          <tns:events>
            <tns:event>
              <tns:eid>someId</tns:eid>
              <tns:eventMessage>someEventMessage</tns:eventMessage>
              <tns:eventSeverity>someEventSeverity</tns:eventSeverity>
              <tns:eventTime>1614974343</tns:eventTime>
              <tns:eventTypeName>eventType</tns:eventTypeName>
              <tns:meterId>meterStayOnTheMeter</tns:meterId>
            </tns:event>
            <tns:event>
              <tns:eid>someId2</tns:eid>
              <tns:eventMessage>someEventMessage2</tns:eventMessage>
              <tns:eventSeverity>someEventSeverity2</tns:eventSeverity>
              <tns:eventTime>1614974344</tns:eventTime>
              <tns:eventTypeName>eventType2</tns:eventTypeName>
              <tns:meterId>meterStayOnTheMeter2</tns:meterId>
            </tns:event>
          </tns:events>
        </tns:receiveEvents>
      </soapenv:Body>
    </soapenv:Envelope>
    

    我使用了一个 curl 命令,比如curl localhost -d @payload -H 'SOAPAction: "receiveEvents"' -H "Content-type: text/xml; charset='UTF-8'"

    【讨论】:

    • 您好帕特里克,感谢您的回复。我知道暴露的代码非常不完整,但我认为这足以解释问题,是的,这是因为你的回答对我很有帮助。现在我有了解决问题的新思路。但是,我有一个新问题,你知道前缀 的含义是什么吗?我该如何修改它或文档来了解它?
    • @Estefanía 在您的示例中,pus 是 xml 名称空间。前缀无关紧要,只要它引用传递的对象中的正确命名空间。 &lt;soapenv:Envelope xmlns:soapenv="http://s.org/soap/envelope/" xmlns:tns="http://p.com/"&gt; &lt;soapenv:Header/&gt; &lt;soapenv:Body&gt; &lt;tns:receiveEvents/&gt;&lt;soapenv:Envelope xmlns:soapenv="http://s.org/soap/envelope/" xmlns:blahblah="http://p.com/"&gt; &lt;soapenv:Header/&gt; &lt;soapenv:Body&gt; &lt;blahblah:receiveEvents&gt; 在功能上是等效的,你的客户端/服务器应该正确地反序列化它们。
    • 谢谢,我没有找到相关信息。现在对我来说很清楚。非常感谢您的回答。
    • @Estefanía 我从来没有遇到过自动生成的 xmlns 的问题,所以我从来没有研究过进一步定制它。我已经使用build_interface_document 在我的服务中处理 http 与 https,看起来您可以在那里编写自己的处理程序来覆盖从 wsdl 生成器返回的数据。除非您有一个真正笨拙的客户与您的服务器交谈,否则您可能不必这样做。
    • 客户端已经存在,我正在尝试尽我所能做我的服务器。谢谢帕特里克,这个链接在我的解决方案中很重要。
    猜你喜欢
    • 1970-01-01
    • 2012-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多