简体   繁体   English

带有 Zeep 的 Python SOAP 客户端 - 导入命名空间

[英]Python SOAP client with Zeep - import namespace

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.我正在开发一个 SOAP 客户端,该客户端与服务器在同一个 Intranet 中运行,但无法访问 Internet。

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:问题:WSDL 包含对位于 Intranet 外部的外部资源的导入('import namespace="schemas.xmlsoap.org/soap/encoding/"'),因此 Zeep 客户端实例化失败:

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?问题:是否可以(并且有意义)在不访问外部资源的情况下创建 Zeep 客户端?

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.作为一个额外的细节,另一个用 Java 编写的客户端,基于 XML rpc ServiceFactory 似乎对这种问题更有弹性,即使没有可用的互联网连接,服务也会被创建(并工作)。 Is it really needed to import the namespace from xmlsoap.org?真的需要从 xmlsoap.org 导入命名空间吗?

Edit, after answer from @mvt:编辑,@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()

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.您可以创建自己的 tranport 类的子类,并向 load() 方法添加额外的逻辑,以便从文件系统重定向/加载特定的 url。

The code is pretty easy i think: https://github.com/mvantellingen/python-zeep/blob/master/src/zeep/transports.py :-)我认为代码很简单: https : //github.com/mvantellingen/python-zeep/blob/master/src/zeep/transports.py :-)

I would suggest doing your custom overriding of the URL and calling load() from the super class.我建议您自定义覆盖 URL 并从超类调用 load()。 This way if the super class code changes ( which it has ), you would not need to refactor your CustomTransport class.这样,如果超类代码发生更改(它已更改),您就不需要重构您的 CustomTransport 类。

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: 此处描述在 zeep 中使用传输的方法,但这里有一个使用 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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM