无法从 WSDL 手动编写简单的 SOAP 请求
Can Not Hand-code Simple SOAP Request from WSDL
我正在编写基于 Salesforce 的 Web 应用程序的客户端(iOS、Swift),我需要通过 SOAP 访问自定义 API。
我正在努力 assemble,根据我从服务器端收到的 WSDL,手动 XML 中的 SOAP 请求。
我对 XML/SOAP 完全没有经验,现在才刚刚开始了解整个 WSDL 的含义。我已阅读 this and this 以及其他介绍性在线文档,但我仍在努力掌握所有新概念。
出于保密原因(暴露我的网络应用程序的内部结构),我不愿意使用任何在线自动生成器,如 this one。
这是我的 WSDL 的相关(我认为)部分:
<definitions targetNamespace="http://soap.sforce.com/schemas/class/[WSDL_File_Name]"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://soap.sforce.com/schemas/class/[WSDL_File_Name]">
<!-- ... -->
<message name="executeXmlRequest">
<part name="parameters" element="tns:executeXml" />
</message>
<!-- ... -->
<binding name="[WSDL_File_Name]Binding" type="tns:[WSDL_File_Name]PortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="executeXml">
<soap:operation soapAction=""/>
<input>
<soap:header use="literal" part="SessionHeader" message="tns:Header"/>
<soap:header use="literal" part="CallOptions" message="tns:Header"/>
<soap:header use="literal" part="DebuggingHeader" message="tns:Header"/>
<soap:header use="literal" part="AllowFieldTruncationHeader" message="tns:Header"/>
<soap:body use="literal" parts="parameters"/>
</input>
<output>
<!-- skipped -->
</output>
</operation>
</binding>
<service name="[WSDL_File_Name]Service">
<documentation></documentation>
<port binding="tns:[WSDL_File_Name]Binding" name="[WSDL_File_Name]">
<soap:address location="https://XXX.salesforce.com/services/Soap/class/[WSDL_File_Name]"/>
</port>
</service>
(我混淆了 [WSDL_File_Name] - WSDL 文件的名称,它也作为前缀出现在这里和那里)。
特别是,我无法理解消息部分:
<message name="executeXmlRequest">
<part name="parameters" element="tns:executeXml" />
</message>
在我在网上找到的大多数示例中(例如,here and here),它通常是 name="body"
(不是 "parameters"
),所以我不太确定如何将其转换为实际的 SOAP 请求的 XML 主体。我试过这个请求正文:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">
<soapenv:Header>
<urn:SessionHeader>
<urn:sessionId>[My OAuth 2.0 Token]</urn:sessionId>
</urn:SessionHeader>
</soapenv:Header>
<soapenv:Body>
<tns:executeXml xmlns:tns="http://soap.sforce.com/schemas/class/[WSDL_File_Name]">
<!-- PAYLOAD HERE (more XML) -->
</tns:executeXml>
</soapenv:Body>
</soapenv:Envelope>
...但我收到 "Argument 1 cannot be null" 错误响应:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://soap.sforce.com/schemas/class/[WSDL_File_Name]">
<soapenv:Body>
<executeXmlResponse>
<result>
<!--
The following inline-XML came from the server with
all entities escaped (e.g., "<" instead of "<");
I replaced them back here for legibility.
-->
<?xml version="1.0" encoding="UTF-8"?>
<response>
<success>false</success>
<exception>
<typeName>System.NullPointerException</typeName>
<message>Argument 1 cannot be null</message>
<stackTrace>Class.[Inbound_Service_Class].Message.<init>: line 271, column 1
Class.[Inbound_Service_Class].parse: line 47, column 1
Class.[Inbound_Service_Class].receive: line 29, column 1
Class.[WSDL_File_Name].executeXml: line 18, column 1
</stackTrace>
</exception>
</response>
<!--
Originally escaped entitied end here
-->
</result>
</executeXmlResponse>
</soapenv:Body>
</soapenv:Envelope>
(同样,特定于应用程序 class names/etc。在方括号中混淆)
那么,我的请求正文应该是什么样的?
澄清:字符串"parameters"出现(作为xml属性值)一共三个整个 WSDL 文件中的次数:
- 输入消息:
<message name="executeXmlRequest"><part name="parameters"...
- 输出消息:
<message name="executeXmlResponse"><part name="parameters"...
- 绑定:
<binding...> ... <soap:body use="literal" parts="parameters"/>...
解决方案:
在 this answer and re-reading all the docs (for example, this page 的内容指导下,我终于意识到 tns:executeXml
标签的内容是在我的 WSDL 的类型部分指定的(抱歉我没有 post 这部分在我的问题中。类型部分很大,我完全跳过了它):
<xsd:element name="executeXml">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="reqXml" type="xsd:string" nillable="true"/>
<!-- ^ THIS GUY... -->
</xsd:sequence>
</xsd:complexType>
</xsd:element>
...所以我认为这会转化为一个带有正文信封的 SOAP 请求,如下所示:
<soapenv:Body>
<tns:executeXml xmlns:tns=\"http://soap.sforce.com/schemas/class/[WSDL_File_Name]">
<!-- ...BECOMES THIS ELEMENT: -->
<tns:reqXml><!-- (MY ESCAPED XML PAYLOAD GOES HERE) --></tns:reqXml>
</tns:executeXml>
</soapenv:Body>
现在我只是收到有关 XML 内容的特定于应用程序的错误消息,我正在 posting,但我可以自己解决。我似乎成功到达 API。
对不起@Sundar,我之前没有提供足够的信息。我接受了你的回答,因为它指引了我正确的方向。
使用像 SOAPUI 这样的工具,有免费版本,将其指向 WSDL 并创建一个新的 soap 项目,然后您可以创建一个带有虚拟值的 soap 请求,获取它并替换为您的值。在我们拥有完整的 WSDL 的情况下,不可能说出请求 xml 中应该包含什么,这就是合同的重点,不是吗。
但是您的错误似乎非常具体,您没有为不应为 null 的特定参数发送 null 值,我认为
我正在编写基于 Salesforce 的 Web 应用程序的客户端(iOS、Swift),我需要通过 SOAP 访问自定义 API。
我正在努力 assemble,根据我从服务器端收到的 WSDL,手动 XML 中的 SOAP 请求。
我对 XML/SOAP 完全没有经验,现在才刚刚开始了解整个 WSDL 的含义。我已阅读 this and this 以及其他介绍性在线文档,但我仍在努力掌握所有新概念。
出于保密原因(暴露我的网络应用程序的内部结构),我不愿意使用任何在线自动生成器,如 this one。
这是我的 WSDL 的相关(我认为)部分:
<definitions targetNamespace="http://soap.sforce.com/schemas/class/[WSDL_File_Name]"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://soap.sforce.com/schemas/class/[WSDL_File_Name]">
<!-- ... -->
<message name="executeXmlRequest">
<part name="parameters" element="tns:executeXml" />
</message>
<!-- ... -->
<binding name="[WSDL_File_Name]Binding" type="tns:[WSDL_File_Name]PortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="executeXml">
<soap:operation soapAction=""/>
<input>
<soap:header use="literal" part="SessionHeader" message="tns:Header"/>
<soap:header use="literal" part="CallOptions" message="tns:Header"/>
<soap:header use="literal" part="DebuggingHeader" message="tns:Header"/>
<soap:header use="literal" part="AllowFieldTruncationHeader" message="tns:Header"/>
<soap:body use="literal" parts="parameters"/>
</input>
<output>
<!-- skipped -->
</output>
</operation>
</binding>
<service name="[WSDL_File_Name]Service">
<documentation></documentation>
<port binding="tns:[WSDL_File_Name]Binding" name="[WSDL_File_Name]">
<soap:address location="https://XXX.salesforce.com/services/Soap/class/[WSDL_File_Name]"/>
</port>
</service>
(我混淆了 [WSDL_File_Name] - WSDL 文件的名称,它也作为前缀出现在这里和那里)。
特别是,我无法理解消息部分:
<message name="executeXmlRequest">
<part name="parameters" element="tns:executeXml" />
</message>
在我在网上找到的大多数示例中(例如,here and here),它通常是 name="body"
(不是 "parameters"
),所以我不太确定如何将其转换为实际的 SOAP 请求的 XML 主体。我试过这个请求正文:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">
<soapenv:Header>
<urn:SessionHeader>
<urn:sessionId>[My OAuth 2.0 Token]</urn:sessionId>
</urn:SessionHeader>
</soapenv:Header>
<soapenv:Body>
<tns:executeXml xmlns:tns="http://soap.sforce.com/schemas/class/[WSDL_File_Name]">
<!-- PAYLOAD HERE (more XML) -->
</tns:executeXml>
</soapenv:Body>
</soapenv:Envelope>
...但我收到 "Argument 1 cannot be null" 错误响应:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://soap.sforce.com/schemas/class/[WSDL_File_Name]">
<soapenv:Body>
<executeXmlResponse>
<result>
<!--
The following inline-XML came from the server with
all entities escaped (e.g., "<" instead of "<");
I replaced them back here for legibility.
-->
<?xml version="1.0" encoding="UTF-8"?>
<response>
<success>false</success>
<exception>
<typeName>System.NullPointerException</typeName>
<message>Argument 1 cannot be null</message>
<stackTrace>Class.[Inbound_Service_Class].Message.<init>: line 271, column 1
Class.[Inbound_Service_Class].parse: line 47, column 1
Class.[Inbound_Service_Class].receive: line 29, column 1
Class.[WSDL_File_Name].executeXml: line 18, column 1
</stackTrace>
</exception>
</response>
<!--
Originally escaped entitied end here
-->
</result>
</executeXmlResponse>
</soapenv:Body>
</soapenv:Envelope>
(同样,特定于应用程序 class names/etc。在方括号中混淆)
那么,我的请求正文应该是什么样的?
澄清:字符串"parameters"出现(作为xml属性值)一共三个整个 WSDL 文件中的次数:
- 输入消息:
<message name="executeXmlRequest"><part name="parameters"...
- 输出消息:
<message name="executeXmlResponse"><part name="parameters"...
- 绑定:
<binding...> ... <soap:body use="literal" parts="parameters"/>...
解决方案:
在 this answer and re-reading all the docs (for example, this page 的内容指导下,我终于意识到 tns:executeXml
标签的内容是在我的 WSDL 的类型部分指定的(抱歉我没有 post 这部分在我的问题中。类型部分很大,我完全跳过了它):
<xsd:element name="executeXml">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="reqXml" type="xsd:string" nillable="true"/>
<!-- ^ THIS GUY... -->
</xsd:sequence>
</xsd:complexType>
</xsd:element>
...所以我认为这会转化为一个带有正文信封的 SOAP 请求,如下所示:
<soapenv:Body>
<tns:executeXml xmlns:tns=\"http://soap.sforce.com/schemas/class/[WSDL_File_Name]">
<!-- ...BECOMES THIS ELEMENT: -->
<tns:reqXml><!-- (MY ESCAPED XML PAYLOAD GOES HERE) --></tns:reqXml>
</tns:executeXml>
</soapenv:Body>
现在我只是收到有关 XML 内容的特定于应用程序的错误消息,我正在 posting,但我可以自己解决。我似乎成功到达 API。
对不起@Sundar,我之前没有提供足够的信息。我接受了你的回答,因为它指引了我正确的方向。
使用像 SOAPUI 这样的工具,有免费版本,将其指向 WSDL 并创建一个新的 soap 项目,然后您可以创建一个带有虚拟值的 soap 请求,获取它并替换为您的值。在我们拥有完整的 WSDL 的情况下,不可能说出请求 xml 中应该包含什么,这就是合同的重点,不是吗。
但是您的错误似乎非常具体,您没有为不应为 null 的特定参数发送 null 值,我认为