Python 带有 Zeep 的 SOAP 客户端 - 导入命名空间
Python SOAP client with Zeep - import namespace
一些背景信息:在解决身份验证问题后,我打开了这个问题 。我更喜欢打开一个新的,以避免用与原始问题无关的评论污染以前的问题,并给予它适当的可见性。
我正在使用与服务器位于同一 Intranet 中的 SOAP 客户端 运行,但无法访问 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)
问题: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',))
问题:是否可以在不访问外部资源的情况下创建 Zeep 客户端?
作为一个额外的细节,另一个用 Java 编写的客户端,基于 XML rpc ServiceFactory 似乎对这类问题更有弹性,服务创建(和工作)即使没有可用的互联网连接。
真的需要从 xmlsoap.org 导入命名空间吗?
编辑,@mvt 回答后:
所以,我选择了建议的解决方案,它允许我同时控制对外部资源的访问(阅读:禁止访问不同于托管端点的服务器)。
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()
您可以创建自己的传输 class 的子class 并向 load() 方法添加额外的逻辑,以便特定的 url 从文件系统。
我认为代码非常简单:https://github.com/mvantellingen/python-zeep/blob/master/src/zeep/transports.py :-)
我建议您自定义覆盖 URL 并从超级 class 调用 load()。这样,如果超级 class 代码更改( 它具有 ),您将不需要重构您的 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)
描述了在 zeep 中使用 Transports 的方法 here,但这里是使用 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()
一些背景信息:在解决身份验证问题后,我打开了这个问题
我正在使用与服务器位于同一 Intranet 中的 SOAP 客户端 运行,但无法访问 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)
问题: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',))
问题:是否可以在不访问外部资源的情况下创建 Zeep 客户端?
作为一个额外的细节,另一个用 Java 编写的客户端,基于 XML rpc ServiceFactory 似乎对这类问题更有弹性,服务创建(和工作)即使没有可用的互联网连接。 真的需要从 xmlsoap.org 导入命名空间吗?
编辑,@mvt 回答后:
所以,我选择了建议的解决方案,它允许我同时控制对外部资源的访问(阅读:禁止访问不同于托管端点的服务器)。
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()
您可以创建自己的传输 class 的子class 并向 load() 方法添加额外的逻辑,以便特定的 url 从文件系统。
我认为代码非常简单:https://github.com/mvantellingen/python-zeep/blob/master/src/zeep/transports.py :-)
我建议您自定义覆盖 URL 并从超级 class 调用 load()。这样,如果超级 class 代码更改( 它具有 ),您将不需要重构您的 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)
描述了在 zeep 中使用 Transports 的方法 here,但这里是使用 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()