【发布时间】:2011-11-21 22:53:08
【问题描述】:
如果给定的 SOAP 标头元素具有给定的值(例如,如果标头标记“响应”的值为“0”),我根本不希望 Apache CXF 返回响应。
我该怎么做? CXF 似乎假设所有调用都会收到响应。
(我知道这在 Web 服务上下文中看起来很奇怪,但如果您的传输是 JMS,它似乎不那么奇怪)。
【问题讨论】:
标签: java web-services jms cxf
如果给定的 SOAP 标头元素具有给定的值(例如,如果标头标记“响应”的值为“0”),我根本不希望 Apache CXF 返回响应。
我该怎么做? CXF 似乎假设所有调用都会收到响应。
(我知道这在 Web 服务上下文中看起来很奇怪,但如果您的传输是 JMS,它似乎不那么奇怪)。
【问题讨论】:
标签: java web-services jms cxf
我已经能够使用一个中止拦截器链的拦截器来做到这一点。
我已经使用 HTTP 配置(WebSphere 返回空的 200)和 ActiveMQ 配置(没有响应返回响应队列)对此进行了测试。
package my.super.interceptor;
public final class Suppressor extends AbstractSoapInterceptor {
public Suppressor() { super(Phase.SETUP); }
@Override
public void handleMessage(final SoapMessage message) throws Fault
{
final boolean suppressResponse = this.suppressResponse(message);
if(suppressResponse) {
log.debug("-> Suppressing response");
message.getInterceptorChain().abort();
}
//if you want to suppress both responses and faults, you need
//to check them separately.
//Change this code to check headers for whatever criteria you want
//(Note you may need to change the super(Phase...) )
//The code's a bit messy here - just sketching out the idea for the answer
private boolean suppressResponse(final Message message) {
final Fault fault = (Fault)message.getContent(Exception.class);
if(fault != null) {
final String faultMessage = fault.getMessage();
return faultMessage.indexOf("Something-you-want-to-match") > 0;
} else {
final MessageInfo messageInfo = (MessageInfo)message.get("org.apache.cxf.service.model.MessageInfo");
final String operation = messageInfo.getOperation().getOutputName();
return operation.indexOf("Something-you-want-to-match") > 0;
}
}
还有你的 applicationContext.xml:
<jaxws:endpoint ...>
<jaxws:outInterceptors>
<bean class="my.super.interceptor.Suppressor"/>
</jaxws:outInterceptors>
<jaxws:outFaultInterceptors>
<bean class="my.super.interceptor.Suppressor"/>
</jaxws:outFaultInterceptors>
</jaxws:endpoint>
【讨论】:
详细解释:从 SOAP 协议规范的角度考虑 SOAP Web 服务。 Web 服务不仅仅是 HTTP 之上的一个花哨的层,它实际上是一种描述双向通信的方式,实现了各种message exchange patterns。以下是最常见的模式:
request-response (In-Out):在 HTTP 环境中,这是一个典型的 HTTP 请求/响应调用,其中一些请求 message 从客户端发送到服务器和一些响应 message 被发回。在 JMS 环境中,您会收到两条独立且独立的消息。
单向(In-Only):在此模型中,客户端发送请求但不期望也不关心响应。在 JMS 中,它相当于发送给代理的简单消息。另一方面,在 HTTP 中(至少这是在 Apache CXF 中实现单向方法的方式),您将在 SEI 上获得 void 方法。而且,CXF默认会使用一个单独的线程池来处理这个请求,所以客户端甚至不等待响应,服务器甚至无法发送响应(因为客户端可能已经断开连接)。
现在是重要的部分:在 WSDL 中,您可以将方法定义为请求/响应(通过定义输入/输出消息)或单向(通过仅提供消息)。这在服务合同中是固定的。您不能创建一个方法一旦返回响应(out message 准确地说)而其他时候则不返回。
显然你可以定义一个可以为空或包含一些内容的 out 消息,但你仍然需要返回一些东西。
简短说明:SOAP 协议不够灵活,无法满足您的要求。您要么返回响应,要么不返回。创建两个方法并选择在客户端调用哪一个,而不是添加自定义标头。
另一个提示:您可以使用 ESB 执行某种转换,以便在存在某些 SOAP 标头时丢弃响应。
【讨论】:
对于您的特定场景,我认为正确的实现方法是使用两个操作。一个用于仅输入,另一个用于输入输出。
您尝试实现它的方式也可能会导致客户端出现问题。现在客户端必须根据请求决定是否寻找响应。另一方面,由于该决定是根据客户端在客户端发送的值做出的,因此它可以决定调用仅输入或输入输出操作。
【讨论】:
@Jared:我基本同意 Tomasz 的解释。我能想到的一种解决方法可以说是否使用 ws-addressing。 ws-addressing 允许您指定<ReplyTo> and <To>。所以基本上,在您不希望将响应发送给已请求的客户端的情况下,服务器端代码可以更改 replyTo 字段的值并可以将响应发送到虚拟 URI。
【讨论】: