SOAP 响应模式验证

Posted

技术标签:

【中文标题】SOAP 响应模式验证【英文标题】:SOAP Response Schema Validation 【发布时间】:2011-04-30 11:22:32 【问题描述】:

短版:

我正在尝试编写一个 XSD 来验证我的 SOAP 服务的响应。我觉得不得不只导入 http://schemas.xmlsoap.org/soap/envelope/ 而不是重新定义信封、头部和正文等 SOAP 元素,但是 Body 的 xmlsoap.org 架构定义对我来说太宽泛了- - 我一导入 SOAP 模式,突然间我的 XSD(我为我的服务精心定制的)验证了所有 SOAP 消息。

我应该如何处理我的 XSD 中 SOAP 信封、头部、主体的定义?

我怀疑问题在于我正在尝试重用我不应该重用的其他模式。当然,这些 SOAP 模式旨在定义(所有)SOAP 消息应该是什么样子。也许我只需要在我的架构中定义我希望我的特定肥皂体看起来像什么。

我可能刚刚回答了我自己的问题。也许有人有不同的解决方案?

加长版:

我在创作 XSD 来描述来自我的一个 SOAP 服务的响应消息时遇到了一点问题。

这是我正在尝试验证的服务响应示例:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <helloResponse xmlns="http://justinfaulkner/wsdl/1.0">
         <Message>Hello, Justin!</Message>
         <Message>Your lucky numbers are: 329, 9</Message>
      </helloResponse>
   </soap:Body>
</soap:Envelope>

我的目标是使用 XSD 验证来自我的服务的响应。 因此,我手工编写了一个 XSD,它描述了属于我的服务的 soap 中的所有类型:Body

<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://justinfaulkner/wsdl/1.0" xmlns:tns="http://justinfaulkner/wsdl/1.0">
   <xsd:complexType name="helloResponseType">
      <xsd:sequence>
         <xsd:element name="Message" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
      </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="helloResponse" type="tns:helloResponseType"/>
</xsd:schema>

当我尝试使用 php 的 DOMDocument::schemaValidateSource() 功能验证带有模式(第二个 sn-p)的示例响应(第一个 XML sn-p)时,验证器指出了我的第一个明显错误:

元素'soap:Envelope':没有匹配的全局声明可用

“哎呀,呃,”我想,“这些元素是在 SOAP 的命名空间中定义的,所以我需要导入 SOAP 的 XSD。”

所以我编辑了我的 XSD 并添加了一个导入:

<xsd:import namespace="http://schemas.xmlsoap.org/soap/envelope/" schemaLocation="http://schemas.xmlsoap.org/soap/envelope/"/>

它成功了!当我使用 XSD 验证 soap 响应时,DOMDocument::schemaValidateSource 返回 true。

然后,作为健全性检查,我采用了不同的肥皂响应 XSD:

<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://justinfaulkner/wsdl/1.0" xmlns:tns="http://justinfaulkner/wsdl/1.0">
   <xsd:import namespace="http://schemas.xmlsoap.org/soap/envelope/" schemaLocation="http://schemas.xmlsoap.org/soap/envelope/"/>
   <xsd:complexType name="OtherServiceResponseType">
      <xsd:all>
         <xsd:element name="CompletionCode" type="xsd:string"/>
         <xsd:element name="ResponseMessage" type="xsd:string"/>
      </xsd:all>
   </xsd:complexType>
   <xsd:element name="OtherServiceResponse" type="tns:OtherServiceResponseType"/>
</xsd:schema>

我试图用这个完全不相关的架构来验证我的肥皂响应......

乍一看根本没有描述此消息的架构也验证了soap响应。

然后我意识到 XSD 的模式一定是响应针对这两种不同模式进行验证的原因。我从 http://schemas.xmlsoap.org/soap/envelope/ 导入的 SOAP 架构将 Body 元素定义为:

<xs:element name="Body" type="tns:Body" />
<xs:complexType name="Body" >
<xs:sequence>
  <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
</xs:sequence>
<xs:anyAttribute namespace="##any" processContents="lax" >
  <xs:annotation>
 <xs:documentation>
   Prose in the spec does not specify that attributes are allowed on the Body element
 </xs:documentation>
  </xs:annotation>
</xs:anyAttribute>
</xs:complexType>

这使得 Body 标签的内容基本上可以是任何东西。

这是有道理的,XSD 的 XSD 的目的是定义所有 XSD 的外观,而不仅仅是我的。

所以我的问题是,我应该如何构建一个 XSD 来验证这些 SOAP 响应,并尽可能重用现有的 SOAP XSD?

这是我一直追求的方向......

我想我可以将 xmlsoap.org 的 XSD 架构抛到窗外,自己重新定义 Envelope 和 Body,具体指定应该在 Body 元素中显示的内容。但我觉得我最终基本上会在我自己的 XSD 中拥有所有肥皂元素的副本,头部和身体的定义略有不同,这感觉像是违反了 DRY。 有没有一种方法可以导入 xmlsoap.org 的 XSD,然后从我的 XSD 中覆盖soap:Body 的定义?

【问题讨论】:

你找到解决这个问题的方法了吗??我有确切的问题。 感谢您的详细帖子。您的解决方案已经对我的具体问题有所帮助。 【参考方案1】:

您应该使用 SOAP Web 服务框架来执行此操作。 wikipedia page 上列出了许多适用于各种编程语言的内容。您编写一个 WSDL 来指定您的 Web 服务 API,并在其中导入您的 XSD 以定义有效负载格式(合同优先方法)。使用框架提供的 wsdl2xxx 工具生成 API stub。您编写 API 实现代码。框架将负责其余的工作(处理 SOAP 消息并绑定到您的实现代码)。

【讨论】:

以上是关于SOAP 响应模式验证的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Karate验证给定XML的SOAP服务XML文件

始终在soap客户端php中作为无效会话令牌获得响应

如何在WPF应用程序中的SOAP客户端的“Set-Cookie”标头响应的新请求中设置“Cookie”标头

使用node-soap连接Bing Ads API

通过 HTTP 标头验证 SOAP 调用

Workday SOAP API:如何进行身份验证