显式和隐式参数_实现隐式和显式SOAP标头

显式和隐式参数

SOAP规范描述SOAP信封可以包含可选的标头部分。 该报头旨在承载不属于实际消息有效负载的数据。 WSDL规范定义了如何声明SOAP标头数据作为Web服务定义的一部分。 在WSDL定义中定义SOAP头有两种方法: 显式和隐式头。

SOAP标头样式

SOAP标头的一种典型用法是传输上下文数据。 例如,如果消息中包含数字签名,则该签名很可能在SOAP头中传输。 另一个示例是针对支持与客户端进行某种形式的会话的Web服务。 一旦建立了这样的会话,他们就要求将特定的标识符与每个请求一起发送。 在WS-AtomicTransaction规范(见相关主题 )也描述了在几个Web服务运行交互的协调序列非常类似的机制。

WSDL规范为您提供了两种不同的方式来指定SOAP头字段的使用。 在显式标头中 ,将所有标头信息添加到服务的portType中。 它作为附加参数公开给客户端。 这种样式的优点是客户端可以将所有信息直接传递给服务。 这种风格的缺点是,它常常使服务的外部接口变得杂乱无章,而这些信息根本与其业务目的无关。

这正是使用隐式标头可以提供帮助的地方:标头信息不是portType的一部分,因此不会影响服务的功能接口。 另一方面,隐式标头很难以编程方式处理。

在深入探讨编程方面的细节之前,让我们看一下如何定义这些不同的样式。

WSDL中的SOAP标头绑定类型

描述不同样式的SOAP头的最简单方法是从一个示例开始。 清单1中的以下WSDL摘录来自上一篇文章,该文章解释了SOAP标头的使用:

清单1. WSDL中的SOAP标头绑定
<wsdl:definitions targetNamespace="http://soapheader.ibm.com" ...>
 <wsdl:types ...>
  <schema elementFormDefault="qualified" ...>
	...
      <element name="quote_timestamp" type="xsd:dateTime" />
  </schema>
 </wsdl:types>
<wsdl:binding name="StockServiceSoapBinding" type="intf:StockService">
      <wsdlsoap:binding style="document" transport=
      "http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="getLastSellPrice">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="getLastSellPriceRequest">
            <wsdlsoap:header message="intf:getLastSellPriceRequest" part=
            "request_header" use="literal"/>
            <wsdlsoap:body parts="parameters" use="literal"/>
         </wsdl:input>
         <wsdl:output name="getLastSellPriceResponse">
            <wsdlsoap:body use="literal"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>
...
</wsdl:definitions>

您可以看到,在WSDL文件的绑定部分中的特定位置,使用了名为<wsdlsoap:header>的元素。 它包含在<wsdl:input>元素中,该元素告诉您在操作的请求消息中有一个SOAP标头部分。 <wsdlsoap:header>元素的内容标识要在标头中传输的消息部分。

这很简单,但这是显式还是隐式标头? 好吧,从上面的摘录中,您无法确切知道。 可能是任何一种方式。 这就是为什么:标头绑定定义消息intf:getLastSellPriceRequest名为request_header的部分进入SOAP信封的标头部分。 标头样式取决于此消息部分是否在Web服务的portType中使用。 让我们详细看看这两种情况。

显式标头

如果标题定义是服务<portType>一部分,则可以显式调用它。 换句话说,必须在portType中的某处使用名为request_header的消息部分,如清单2所示:

清单2. WSDL中的显式SOAP标头
<wsdl:message name="getLastSellPriceRequest">
      <wsdl:part element="intf:getLastSellPrice" name="parameters"/>
      <wsdl:part name="request_header" element="intf:quote_timestamp"/>
   </wsdl:message>

   <wsdl:message name="getLastSellPriceResponse">
      <wsdl:part element="intf:getLastSellPriceResponse" name="parameters"/>
   </wsdl:message>

   <wsdl:portType name="StockService">
      <wsdl:operation name="getLastSellPrice">
         <wsdl:input message="intf:getLastSellPriceRequest" name=
         "getLastSellPriceRequest"/>
         <wsdl:output message="intf:getLastSellPriceResponse" name=
         "getLastSellPriceResponse"/>
      </wsdl:operation>
   </wsdl:portType>

请注意,名为getLastSellPriceRequest的消息包含两个部分。 一部分进入SOAP请求消息的主体部分,另一部分进入标头。 清单3显示了WSDL文件的相关部分,该部分显示了两个部分:

清单3. WSDL中的显式SOAP标头-SOAP绑定
<wsdl:input name="getLastSellPriceRequest">
      <wsdlsoap:header message="intf:getLastSellPriceRequest" part=
      "request_header" use="literal"/>
      <wsdlsoap:body parts="parameters" use="literal"/>
</wsdl:input>

<portType>元素定义Web服务的外部接口。 它定义了哪些数据作为请求消息的一部分发送。 如果某些请求数据在请求消息的SOAP标头部分中传输,则可以将其称为显式标头。 对于将响应消息的部分(或全部)分别定义为标头元素的情况,也是如此。

隐式标题

这种情况很简单,对吧? 如果在标题中传输的消息部分未显示在<portType>元素的任何位置,则您具有隐式标题。 清单4显示了可能的样子:

清单4. WSDL中的隐式SOAP标头
<wsdl:message name="getLastSellPriceRequest">
      <wsdl:part element="intf:getLastSellPrice" name="parameters"/>
   </wsdl:message>
   
   <wsdl:message name="getLastSellPriceResponse">
      <wsdl:part element="intf:getLastSellPriceResponse" name="parameters"/>
   </wsdl:message>

   <wsdl:message name="getLastSellPriceRequestHeader">
      <wsdl:part name="request_header" element="intf:quote_timestamp"/>
   </wsdl:message>

   <wsdl:portType name="StockService">
      <wsdl:operation name="getLastSellPrice">
         <wsdl:input message="intf:getLastSellPriceRequest" name=
         "getLastSellPriceRequest"/>
         <wsdl:output message="intf:getLastSellPriceResponse" name=
         "getLastSellPriceResponse"/>
      </wsdl:operation>
   </wsdl:portType>

清单显示了定义的三个消息,在<portType>仅使用了其中两个。 第三个名称叫getLastSellPriceRequestHeader ,根本没有使用。 现在假设SOAP绑定看起来像清单5所示:

清单5. WSDL中的隐式SOAP标头-SOAP绑定
<wsdl:input name="getLastSellPriceRequest">
      <wsdlsoap:header message="intf:getLastSellPriceRequestHeader" part=
      "request_header" use="literal"/>
      <wsdlsoap:body parts="parameters" use="literal"/>
</wsdl:input>

同样, <wsdlsoap:header>元素引用<portType>未使用的消息部分。 因此,您有一个隐式标头。

SOAP消息表示

请注意,每种类型的SOAP标头的有线格式都相同:信息在消息的SOAP标头部分中承载。 换句话说,在查看SOAP消息时,您无法分辨它是在关联的WSDL定义中定义为隐式还是显式头。 清单6显示了示例Web服务的SOAP消息:

清单6.带标头的SOAP消息
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ...>
	<soapenv:Header>
	     <p677:quote_timestamp xmlns:p677=
	     "http://soapheader.ibm.com">2005-01-03T06:00:00.000Z</p677:quote_timestamp>
	</soapenv:Header>
	<soapenv:Body>
		<p677:getLastSellPrice xmlns:p677="http://soapheader.ibm.com">
			<p677:ticker>IBM</p677:ticker>
		</p677:getLastSellPrice>
	</soapenv:Body>
</soapenv:Envelope>

显式和隐式标头的JAX-RPC映射

现在,您已经定义了两种标题样式,如果您正在使用JAX-RPC开发Web服务,这意味着什么? JAX-RPC规范讨论了称为隐式和显式服务上下文的事物。 即使服务上下文可能会或可能不会映射到SOAP标头定义中,您仍可以在此处安全地假定它们的含义相同。 然后,规范描述了显式服务上下文如何映射到服务的远程接口,而隐式上下文通常不是。

实际上,这意味着显式标头(或服务上下文)相对容易处理,因为它们被映射到Web服务的服务端点接口 (SEI)。 在SOAP头中传输的消息部分成为SEI的附加参数。 例如,具有上面明确定义的WSDL的SEI类似于清单7所示:

清单7.显式标头类型的服务端点接口
public interface StockServiceExplicit_PortType extends java.rmi.Remote {
    public com.ibm.soapheader.GetLastSellPriceResponse 
      getLastSellPrice(com.ibm.soapheader.GetLastSellPrice parameters, 
          java.util.Calendar request_header) 
              throws java.rmi.RemoteException;
}

在运行时,将作为request_header参数传入的值放入请求消息的SOAP标头中。

您现在可能已经可以猜出该接口在隐式标头情况下的样子。 根本没有引用标头消息部分! 该工具只是忽略它并生成清单8所示的SEI:

清单8.隐式标头类型的服务端点接口
public interface StockServiceImplicit_PortType extends java.rmi.Remote {
 public float getLastSellPrice(java.lang.String ticker) throws java.rmi.RemoteException;
}

尽管我在本文中不做进一步介绍,但有趣的是,在这种情况下,输入和输出参数没有像以前那样包装到新类中。

Java编程中的隐式标头处理

那么,如何处理在JAX-RPC中定义隐式标头的Web服务呢? 该规范对您无济于事,因为只有portType中包含的那些元素才会生成到服务端点接口中。

除此之外,不同的JAX-RPC供应商可能会提供不同级别的支持。 处理隐式标头的一种方法是使用JAX-RPC处理程序来管理标头的内容。 处理程序在客户端和服务器端都可以完全访问SOAP消息,包括标头。 但是如何将正确的内容从客户端应用程序传递到处理程序? 您可以在javax.xml.rpc.Stub接口上使用_setProperty()将信息传递给客户端代理对象。 从那里,处理程序可以使用javax.xml.rpc.handler.SOAPMessageContext.getProperty()方法检索它。 本文随附的示例向您展示了这种机制(单击本文顶部或底部的代码图标以下载EAR文件)。

在服务器端,您还可以使用JAX-RPC处理程序来处理隐式标头。 此外,您可以通过javax.xml.rpc.server.ServiceLifecycle接口将SOAP标头信息传递到服务实现中。 在本系列的上一个技巧中,我解释了如何使用此界面。 再次,请参考示例代码中的完整示例。

摘要

定义Web服务中SOAP头字段的使用有两种不同的方法,即隐式和显式头。 两者之间的差异在WSDL定义中很容易检测到。 尽管这可能只是次要的设计细节,但对生成的JAX-RPC Java代码有重大影响。 特别是在隐式标头的情况下,必须编写(或生成)额外的代码来处理不属于portType的标头信息。


翻译自: https://www.ibm.com/developerworks/xml/library/ws-tip-headers/index.html

显式和隐式参数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值