Python SOAP client with Zeep - import namespace

时光总嘲笑我的痴心妄想 提交于 2019-12-06 04:05:37

问题


A little context: I am opening this question arose here, after solving an authentication problem. I prefer to open a new one to avoid polluting the previous with comments not related to the original issue, and to give it the proper visibility.

I am working on a SOAP client running in the same intranet as the server, without internet access.

from requests.auth import HTTPBasicAuth
from zeep import Client
from zeep.transports import Transport

wsdl = 'http://mysite.dom/services/MyWebServices?WSDL'
client = Client(wsdl, transport=HTTPBasicAuth('user','pass'), cache=None)

The problem: WSDL contains an import to an external resource located outside the intranet ('import namespace="schemas.xmlsoap.org/soap/encoding/"') and therefore Zeep Client instantiation fails with:

Exception: HTTPConnectionPool(host='schemas.xmlsoap.org', port=80): Max retries exceeded with url: /soap/encoding/ (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7f3dab9d30b8>: Failed to establish a new connection: [Errno 110] Connection timed out',))

Question: is it possible (and does it make sense) to create the Zeep Client without accessing the external resource?

As an additional detail, another client written in Java, based on XML rpc ServiceFactory seems to be more resilient to this kind of problem, the service is created (and works) even if no internet connection is available. Is it really needed to import the namespace from xmlsoap.org?

Edit, after answer from @mvt:

So, I went for the proposed solution, which allows me at the same time to control the access to external resources (read: forbid access to servers different from the one hosting the endpoint).

class MyTransport(zeep.Transport):
    def load(self, url):
        if not url:
            raise ValueError("No url given to load")
        parsed_url = urlparse(url)
        if parsed_url.scheme in ('http', 'https'):
            if parsed_url.netloc == "myserver.ext":
                response = self.session.get(url, timeout=self.load_timeout)
                response.raise_for_status()
                return response.content
            elif url == "http://schemas.xmlsoap.org/soap/encoding/":
                url = "/some/path/myfile.xsd"
            else:
                raise
        elif parsed_url.scheme == 'file':
            if url.startswith('file://'):
                url = url[7:]
        with open(os.path.expanduser(url), 'rb') as fh:
            return fh.read()

回答1:


You could create your own subclass of the tranport class and add additional logic to the load() method so that specific url's are redirected / loaded from the filesystem.

The code is pretty easy i think: https://github.com/mvantellingen/python-zeep/blob/master/src/zeep/transports.py :-)




回答2:


I would suggest doing your custom overriding of the URL and calling load() from the super class. This way if the super class code changes (which it has), you would not need to refactor your CustomTransport class.

from zeep.transports import Transport

class CustomTransport(Transport):
    def load(self, url):
        # Custom URL overriding to local file storage
        if url and url == "http://schemas.xmlsoap.org/soap/encoding/":
            url = "/path/to/schemas.xmlsoap.org.xsd"

        # Call zeep.transports.Transport's load()
        return super(CustomTransport, self).load(url)

The way to use the Transports in zeep is described here, but here is a quick example of using the CustomTransport:

from requests import Session
from requests.auth import HTTPBasicAuth
from zeep import Client

session = Session()
client = Client('http://example.com/production.svc?wsdl', transport=CustomTransport(session=session))
client.service.foo()


来源:https://stackoverflow.com/questions/40220134/python-soap-client-with-zeep-import-namespace

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!