В моем приложении мне нужно получить доступ к внутреннему (корпоративному) Soap API. Для этого доступа я использовал Zeep до сих пор. Но теперь доступ должен проходить через прокси, и фактический адрес API должен быть преобразован в виртуальный адрес прокси.
Создание клиента Zeep также работает правильно, и я могу получить доступ к файлам WSDL. Однако проблема возникает при вызове соответствующей службы, потому что Zeep берет соответствующий URL-адрес из файла WSDL, и он не соответствует виртуальному адресу прокси.
Я попытаюсь проиллюстрировать проблему ниже с помощью моего конкретного кода:
Предположим, что адрес SOAP API — https://original-soap/wsdl?service=<service_name>
.
В прокси есть отображение из https://origial-soap
в http://virtual-soap
.
Таким образом, Zeep должен использовать адрес http://virtual-soap/wsdl?service=<service_name>
.
Я инициализирую свой клиент Zeep следующим образом:
from requests.auth import HTTPBasicAuth
from requests import Session
from zeep import Client
from zeep.transports import Transport
from zeep.helpers import serialize_object
session = Session()
session.proxies = {
'http': 'http://<proxy_host>:<proxy_port>',
'https': 'http://<proxy_host>:<proxy_port>',
}
proxy_header = {
"Proxy-Authorization": "Bearer <proxy_access_token>"
}
session.headers.update(proxy_header)
session.verify = False
session.auth = HTTPBasicAuth(<soap_user>, <soap_password>)
transport = Transport(session=session)
client = Client(wsdl='http://virtual-saop/wsdl?service=<service_name>', transport=transport)
print('CLIENT INITIALIZED') # <-- This print command is executed
soap_result = client.service['<service_function_name>'](<function parameters>) # <-- Connectivity errors occur here
Итак, мой вопрос заключается в том, как я могу также изменить URL-адрес, который Zeep использует при вызове службы, чтобы здесь также использовался виртуальный адрес.
Спасибо за любую помощь заранее!
Благодаря @Bogdan я решил проблему, используя следующий код для инициализации службы:
service = client.create_service(
client.service._binding.name, client.service._binding_options['address'].replace('https://original-soap:443', 'http://virtual-soap:80', 1)
)
Есть еще один способ создать ServiceProxy, который должен это делать.
См. документацию по адресу https://docs.python-zeep.org/en/master/client.html#creating-new-serviceproxy-objects
Экземпляр ServiceProxy по умолчанию создается с использованием адреса в WSDL, но описанный выше способ создания ServiceProxy позволяет больше контролировать адрес.
Значение для {http://my-target-namespace-here}myBinding
— это ваш идентификатор привязки. Если вы сделаете python -mzeep https://original-soap/wsdl
, вы должны получить вывод, подобный этому (я использую здесь какой-то онлайн-пример для демонстрационных целей, поскольку у меня нет доступа к вашему WSDL):
> python -mzeep http://www.dneonline.com/calculator.asmx?WSDL
Prefixes:
xsd: http://www.w3.org/2001/XMLSchema
ns0: http://tempuri.org/
Global elements:
ns0:Add(intA: xsd:int, intB: xsd:int)
ns0:AddResponse(AddResult: xsd:int)
ns0:Divide(intA: xsd:int, intB: xsd:int)
ns0:DivideResponse(DivideResult: xsd:int)
ns0:Multiply(intA: xsd:int, intB: xsd:int)
ns0:MultiplyResponse(MultiplyResult: xsd:int)
ns0:Subtract(intA: xsd:int, intB: xsd:int)
ns0:SubtractResponse(SubtractResult: xsd:int)
Global types:
xsd:anyType
xsd:ENTITIES
xsd:ENTITY
xsd:ID
xsd:IDREF
xsd:IDREFS
xsd:NCName
xsd:NMTOKEN
xsd:NMTOKENS
xsd:NOTATION
xsd:Name
xsd:QName
xsd:anySimpleType
xsd:anyURI
xsd:base64Binary
xsd:boolean
xsd:byte
xsd:date
xsd:dateTime
xsd:decimal
xsd:double
xsd:duration
xsd:float
xsd:gDay
xsd:gMonth
xsd:gMonthDay
xsd:gYear
xsd:gYearMonth
xsd:hexBinary
xsd:int
xsd:integer
xsd:language
xsd:long
xsd:negativeInteger
xsd:nonNegativeInteger
xsd:nonPositiveInteger
xsd:normalizedString
xsd:positiveInteger
xsd:short
xsd:string
xsd:time
xsd:token
xsd:unsignedByte
xsd:unsignedInt
xsd:unsignedLong
xsd:unsignedShort
Bindings:
Soap11Binding: {http://tempuri.org/}CalculatorSoap
Soap12Binding: {http://tempuri.org/}CalculatorSoap12
Service: Calculator
Port: CalculatorSoap (Soap11Binding: {http://tempuri.org/}CalculatorSoap)
Operations:
Add(intA: xsd:int, intB: xsd:int) -> AddResult: xsd:int
Divide(intA: xsd:int, intB: xsd:int) -> DivideResult: xsd:int
Multiply(intA: xsd:int, intB: xsd:int) -> MultiplyResult: xsd:int
Subtract(intA: xsd:int, intB: xsd:int) -> SubtractResult: xsd:int
Port: CalculatorSoap12 (Soap12Binding: {http://tempuri.org/}CalculatorSoap12)
Operations:
Add(intA: xsd:int, intB: xsd:int) -> AddResult: xsd:int
Divide(intA: xsd:int, intB: xsd:int) -> DivideResult: xsd:int
Multiply(intA: xsd:int, intB: xsd:int) -> MultiplyResult: xsd:int
Subtract(intA: xsd:int, intB: xsd:int) -> SubtractResult: xsd:int
Если вы посмотрите на результат этого при выполнении команды на вашем WSDL, вы увидите раздел «Привязки». Вот откуда вы получаете значение, которое, скорее всего, будет для Soap11Binding
(большинство сервисов предоставляют только одну привязку, этот предоставляет две, по одной для каждой версии протокола SOAP).
Для http://my-endpoint.com/acceptance/
в документации вы должны заменить свой новый адрес SOAP (то есть новое место, куда вы хотите отправить запрос на обслуживание сейчас). Судя по вашему примеру, это должно быть http://virtual-soap/something
, где something
— это исходный путь от исходного адреса SOAP, который находится внутри WSDL (опять же, поскольку у меня нет доступа к вашему WSDL, вы должны посмотреть, какую часть адреса вы нужно заменить, а что останется).
Что касается того, какую операцию вы хотите вызвать, это не меняется. Вы называете это так же. Те же методы существуют, потому что вы не меняете контракт на обслуживание, вы просто меняете, куда вы хотите отправить запрос.
Здравствуйте @Bodgan, большое спасибо за ваш ответ. К сожалению, я не полностью понимаю документацию. Не могли бы вы привести пример инициализации службы? Что означают
'{http://my-target-namespace-here}myBinding'
и'http://my-endpoint.com/acceptance/'
? И где мне указать имя операции, которую я хочу вызвать?