通过 Zeep 使用代理访问 SOAP 时更改服务 URL

huangapple go评论73阅读模式
英文:

Changing the service URL when accessing SOAP via a proxy using Zeep

问题

在我的应用程序中,我需要访问一个内部(企业)的SOAP API。为了实现这个访问,我迄今为止一直使用的是Zeep。但现在访问必须经过代理,并且API的实际地址必须转换为代理的虚拟地址。

创建Zeep客户端也能正常工作,我可以访问WSDL文件。然而,问题出现在调用相应的服务时,因为Zeep从WSDL文件中获取相应的URL,而这个URL与代理的虚拟地址不匹配。

我会尝试用我的具体代码来说明这个问题:

假设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

所以我的问题是如何更改Zeep调用服务时使用的URL,以便在这里也使用虚拟地址。

在此先感谢任何提前提供的帮助!

感谢@Bogdan,我通过使用以下代码解决了这个问题来初始化服务:

service = client.create_service(
    client.service._binding.name, client.service._binding_options['address'].replace('https://original-soap:443', 'http://virtual-soap:80', 1)
)
英文:

Within my application, I need to access an internal (corporate) Soap API. For this access I have used Zeep so far. But now the access has to go through a proxy and the actual address of the API has to be converted to a virtual address of the proxy.

Creating the Zeep client also works correctly and I can access the WSDL files. However, the problem occurs when calling the respective service, because Zeep takes the corresponding URL from the WSDL file and this does not match the virtual address of the proxy.

I'll try to illustrate the problem below with my concrete code:

Assuming the address of the SOAP API is https://original-soap/wsdl?service=<service_name>.

In the proxy there is a mapping from https://origial-soap to http://virtual-soap.

So the address Zeep should use then is http://virtual-soap/wsdl?service=<service_name>.

I initialize my Zeep client as follows:

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

So my question is how I can also change the URL that Zeep uses when calling the service so that the virtual address is used here as well.

Thanks for any help in advance!

Thanks to @Bogdan, I solved the problem using the following code for the service initialization:

service = client.create_service(
    client.service._binding.name, client.service._binding_options['address'].replace('https://original-soap:443', 'http://virtual-soap:80', 1)
)

答案1

得分: 0

以下是翻译好的部分:

有另一种创建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的结果,您将看到一个“Bindings”部分。那是您获取值的地方,很可能是`Soap11Binding`(大多数服务提供一个绑定,这个提供两个,每个版本的SOAP协议一个)。

对于文档中的`http://my-endpoint.com/acceptance/`,您应该替换为新的SOAP地址(即您现在要发送服务请求的新位置)。根据您的示例,这应该是`http://virtual-soap/something`,其中`something` 是原始SOAP地址中的原始路径(再次强调,因为我无法访问您的WSDL,您应该查看哪部分地址需要替换,哪部分保持不变)。

至于您想要调用的操作,它不会改变。您调用方式相同。因为您不会更改服务契约,只会更改请求的发送位置。

<details>
<summary>英文:</summary>

There is another way to create the ServiceProxy that&#39;s supposed to do that. 

See the documentation at https://docs.python-zeep.org/en/master/client.html#creating-new-serviceproxy-objects

The default ServiceProxy instance is created using the address in the WSDL, but the above way of creating the ServiceProxy allows more control on the address.

The value for `{http://my-target-namespace-here}myBinding` is your binding identifier. If you do a `python -mzeep https://original-soap/wsdl` you should get an output like this one (I&#39;m using some online example here for demonstration purposes, since I don&#39;t have access to your WSDL):

    &gt; 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) -&gt; AddResult: xsd:int
                Divide(intA: xsd:int, intB: xsd:int) -&gt; DivideResult: xsd:int
                Multiply(intA: xsd:int, intB: xsd:int) -&gt; MultiplyResult: xsd:int
                Subtract(intA: xsd:int, intB: xsd:int) -&gt; SubtractResult: xsd:int
    
         Port: CalculatorSoap12 (Soap12Binding: {http://tempuri.org/}CalculatorSoap12)
             Operations:
                Add(intA: xsd:int, intB: xsd:int) -&gt; AddResult: xsd:int
                Divide(intA: xsd:int, intB: xsd:int) -&gt; DivideResult: xsd:int
                Multiply(intA: xsd:int, intB: xsd:int) -&gt; MultiplyResult: xsd:int
                Subtract(intA: xsd:int, intB: xsd:int) -&gt; SubtractResult: xsd:int


If you look at the result of this when running the command on your WSDL, you will see a &quot;Bindings&quot; section. That&#39;s from where you get the value, which most likely will be the one for the `Soap11Binding` (most services will provide just one binding, this one provides two, one for each version of the SOAP protocol).

For the `http://my-endpoint.com/acceptance/` in the documentation, you should replace your new SOAP address (i.e. the new place where you want to send the service request now). Judging from your example, this should be `http://virtual-soap/something`, where `something` is the original path from the original SOAP address that&#39;s inside the WSDL (again, since I don&#39;t have access to you WSDL, you should look to see which part of the address you need to replace, and which stays the same).

As for what operation you want to call, that doesn&#39;t changes. You call it the same way. The same methods are there because you don&#39;t change the service contract, you just change where you want to send the request to.


</details>



huangapple
  • 本文由 发表于 2023年4月13日 15:08:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76002579.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定