2011-10-17 46 views

回答

10

参考:(感谢道格赫尔曼)building soap service

的Zolera皂基础建设(ZSI),是pywebsvcs项目的一部分。它提供了完整的服务器和客户端库来处理SOAP。为了使用它,开发人员编写WSDL文件(手动或使用WSDL编辑器),然后为客户端生成Python源代码并为服务器生成存根。 WSDL文件中定义的数据结构被转换为可在客户端和服务器代码中使用的Python类。

我们实现了一个简单的echo服务,该服务作为输出返回,无论它从客户端获得什么输入。清单1包含了该服务的ZSI版本的手工WSDL输入。

清单1

<?xml version="1.0" encoding="UTF-8"?> 
<definitions 
    xmlns="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:tns="urn:ZSI" 
    targetNamespace="urn:ZSI" > 

    <types> 
    <xsd:schema elementFormDefault="qualified" 
     targetNamespace="urn:ZSI"> 
     <xsd:element name="Echo"> 
     <xsd:complexType> 
      <xsd:sequence> 
      <xsd:element name="value" type="xsd:anyType"/> 
      </xsd:sequence> 
     </xsd:complexType> 
     </xsd:element> 
    </xsd:schema> 
    </types> 

    <message name="EchoRequest"> 
    <part name="parameters" element="tns:Echo" /> 
    </message> 
    <message name="EchoResponse"> 
    <part name="parameters" element="tns:Echo"/> 
    </message> 

    <portType name="EchoServer"> 
    <operation name="Echo"> 
     <input message="tns:EchoRequest"/> 
     <output message="tns:EchoResponse"/> 
    </operation> 
    </portType> 

    <binding name="EchoServer" type="tns:EchoServer"> 
    <soap:binding style="document" 
        transport="http://schemas.xmlsoap.org/soap/http"/> 
    <operation name="Echo"> 
     <soap:operation soapAction="Echo"/> 
     <input> 
     <soap:body use="literal"/> 
     </input> 
     <output> 
     <soap:body use="literal"/> 
     </output> 
    </operation> 
    </binding> 

    <service name="EchoServer"> 
    <port name="EchoServer" binding="tns:EchoServer"> 
     <soap:address location="http://localhost:7000"/> 
    </port> 
    </service> 

</definitions> 

为了生成从WSDL客户端和服务器代码,它馈送到wsdl2py程序(包含在ZSI)。要添加对复杂类型的支持,请添加-b选项,但对于此简单示例不是必需的。 wsdl2py会,响应,产生三个文件:

清单2

EchoServer_client.py是建立一个客户端的SimpleEcho Web服务所需的代码。

################################################## 
# file: EchoServer_client.py 
# 
# client stubs generated by 
# "ZSI.generate.wsdl2python.WriteServiceModule" 
# 
################################################## 

from EchoServer_types import * 
import urlparse, types 
from ZSI.TCcompound import ComplexType, Struct 
from ZSI import client 
from ZSI.schema import GED, GTD 
import ZSI 
from ZSI.generate.pyclass import pyclass_type 

# Locator 
class EchoServerLocator: 
    EchoServer_address = "http://localhost:7000" 
    def getEchoServerAddress(self): 
     return EchoServerLocator.EchoServer_address 
    def getEchoServer(self, url=None, **kw): 
     return EchoServerSOAP(
      url or EchoServerLocator.EchoServer_address, 
      **kw) 

# Methods 
class EchoServerSOAP: 
    def __init__(self, url, **kw): 
     kw.setdefault("readerclass", None) 
     kw.setdefault("writerclass", None) 
     # no resource properties 
     self.binding = client.Binding(url=url, **kw) 
     # no ws-addressing 

    # op: Echo 
    def Echo(self, request, **kw): 
     if isinstance(request, EchoRequest) is False: 
      raise TypeError, "%s incorrect request type" % \ 
       (request.__class__) 
     # no input wsaction 
     self.binding.Send(None, None, request, soapaction="Echo", **kw) 
     # no output wsaction 
     response = self.binding.Receive(EchoResponse.typecode) 
     return response 

EchoRequest = GED("urn:ZSI", "Echo").pyclass 

EchoResponse = GED("urn:ZSI", "Echo").pyclass 

清单3

EchoServer_server.py包含构建SimpleEcho Web服务的服务器所需的代码。

################################################## 
# file: EchoServer_server.py 
# 
# skeleton generated by 
# "ZSI.generate.wsdl2dispatch.ServiceModuleWriter" 
# 
################################################## 

from ZSI.schema import GED, GTD 
from ZSI.TCcompound import ComplexType, Struct 
from EchoServer_types import * 
from ZSI.ServiceContainer import ServiceSOAPBinding 

# Messages 
EchoRequest = GED("urn:ZSI", "Echo").pyclass 

EchoResponse = GED("urn:ZSI", "Echo").pyclass 


# Service Skeletons 
class EchoServer(ServiceSOAPBinding): 
    soapAction = {} 
    root = {} 

    def __init__(self, post='', **kw): 
     ServiceSOAPBinding.__init__(self, post) 

    def soap_Echo(self, ps, **kw): 
     request = ps.Parse(EchoRequest.typecode) 
     return request,EchoResponse() 

    soapAction['Echo'] = 'soap_Echo' 
    root[(EchoRequest.typecode.nspname,EchoRequest.typecode.pname)] = \ 
     'soap_Echo' 

清单4

EchoServer_types.py具有类型由客户端和服务器代码中都使用的定义。

################################################## 
# file: EchoServer_types.py 
# 
# schema types generated by 
# "ZSI.generate.wsdl2python.WriteServiceModule" 
# 
################################################## 

import ZSI 
import ZSI.TCcompound 
from ZSI.schema import (LocalElementDeclaration, ElementDeclaration, 
         TypeDefinition, GTD, GED) 
from ZSI.generate.pyclass import pyclass_type 

############################## 
# targetNamespace 
# urn:ZSI 
############################## 

class ns0: 
    targetNamespace = "urn:ZSI" 

    class Echo_Dec(ZSI.TCcompound.ComplexType, ElementDeclaration): 
     literal = "Echo" 
     schema = "urn:ZSI" 
     def __init__(self, **kw): 
      ns = ns0.Echo_Dec.schema 
      TClist = [ZSI.TC.AnyType(pname=(ns,"value"), 
         aname="_value", minOccurs=1, maxOccurs=1, 
         nillable=False, typed=False, 
         encoded=kw.get("encoded"))] 
      kw["pname"] = ("urn:ZSI","Echo") 
      kw["aname"] = "_Echo" 
      self.attribute_typecode_dict = {} 
      ZSI.TCcompound.ComplexType.__init__(self,None,TClist, 
               inorder=0,**kw) 
      class Holder: 
       __metaclass__ = pyclass_type 
       typecode = self 
       def __init__(self): 
        # pyclass 
        self._value = None 
        return 
      Holder.__name__ = "Echo_Holder" 
      self.pyclass = Holder 

# end class ns0 (tns: urn:ZSI) 

一旦产生,这些文件并不意味着被编辑,因为它们将被再生为一个构建过程每当WSDL输入的变化的一部分。随着更多类型和调用被添加到服务定义中,文件中的代码会不断增加。

服务器的实现进入单独的文件,导入生成的代码。在这个例子中,实际的服务位于清单5的第18-25行。@soapmethod装饰器定义了调用的输入(EchoRequest)和输出(EchoResponse)。在该示例中,soap_Echo()的实现只是使用请求值填充响应值,并返回请求和响应。从那里,ZSI负责构建SOAP响应并将其发送回客户端。

清单5

import os 
import sys 
from EchoServer_client import * 
from ZSI.twisted.wsgi import (SOAPApplication, 
           soapmethod, 
           SOAPHandlerChainFactory) 

class EchoService(SOAPApplication): 
    factory = SOAPHandlerChainFactory 
    wsdl_content = dict(name='Echo', 
         targetNamespace='urn:echo', 
         imports=(), 
         portType='', 
         ) 

    def __call__(self, env, start_response): 
     self.env = env 
     return SOAPApplication.__call__(self, env, start_response) 

    @soapmethod(EchoRequest.typecode, 
       EchoResponse.typecode, 
       operation='Echo', 
       soapaction='Echo') 
    def soap_Echo(self, request, response, **kw): 
     # Just return what was sent 
     response.Value = request.Value 
     return request, response 

def main(): 
    from wsgiref.simple_server import make_server 
    from ZSI.twisted.wsgi import WSGIApplication 

    application   = WSGIApplication() 
    httpd    = make_server('', 7000, application) 
    application['echo'] = EchoService() 
    print "listening..." 
    httpd.serve_forever() 

if __name__ == '__main__': 
    main() 

清单6包括如何使用ZSI客户端库从客户端访问服务器的样品。所有需要完成的工作是创建EchoServer Web服务的句柄,构建EchoRequest,将其发送到Web服务并读取响应。

from EchoServer_client import * 
import sys, time 

loc = EchoServerLocator() 
port = loc.getEchoServer(url='http://localhost:7000/echo') 

print "Echo: ", 
msg = EchoRequest() 
msg.Value = "Is there an echo in here?" 
rsp = port.Echo(msg) 
print rsp.Value 
相关问题