当前位置: 首页 > 知识库问答 >
问题:

CXF:如何从CXF客户端重新发送原始请求?

司徒杜吟
2023-03-14

我是SOA开发环境中CXF的用户。

我想知道我的问题是否有CXF的解决方案。这是我的需要。我们开发了一个服务于JAXWSendpoint的webapp,endpoint实现包括通过拦截器分析请求,将请求中的数据存储到Java服务层的数据库中,并通过CXF客户端将原始请求重新发送到另一台服务器。关键是我们的一些请求包含DSIG签名(https://www.w3.org/TR/xmldsig-core/)或签名的SAML断言。我们需要在不改变CXFClient中的请求(例如代理)的情况下重新发送请求。CXF用于将封送处理的对象发送到服务器,但这样就不会发送原始流

有没有一种方法可以在不改变Java CXFClient的情况下从服务层重新发送传入请求(签名取决于请求的格式:空格、名称空间前缀、回车等)?我们更喜欢CXFClient,因为我们希望重用自制的CXF拦截器,该拦截器记录传出请求。

我们测试了一个拦截器,打算在将输出流发送到服务器之前用原始请求替换输出流,我们使用了以下答案:如何修改出站CXF请求的原始XML消息?,但我们仍然是KO,CXF仍然发送从编组对象生成的流。请参见下面的代码。

上下文:-CXF 2.7.18(JDK 6)和3.1.10(JDK 8)-平台:windows 7 64位/rhel 7 64位-Apache Tomcat 7-用于分析传入流量的Tcpdump

我们客户的代码示例:

    final Client cxfClient = org.apache.cxf.frontend.ClientProxy.getClient( portType );
    cxfClient.getInInterceptors().clear();
cxfClient.getOutInterceptors().clear();
cxfClient.getOutFaultInterceptors().clear();
cxfClient.getRequestContext().put(CustomStreamerInterceptor.STREAM_TO_SEND,
PhaseInterceptorChain.getCurrentMessage().getContent( InputStream.class ) );
cxfClient.getOutInterceptors().add( new CustomStreamerInterceptor() );
org.apache.cxf.transport.http.HTTPConduit http = (org.apache.cxf.transport.http.HTTPConduit) cxfClient.getConduit();
...
port.doSomething(someRequest);

CustomStreamrinterceptor:

package test;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.binding.soap.interceptor.SoapOutInterceptor.SoapOutEndingInterceptor;
import org.apache.cxf.helpers.LoadingByteArrayOutputStream;
import org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.io.CacheAndWriteOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.Phase;
public class CustomStreamerInterceptor extends AbstractOutDatabindingInterceptor {
       public static final String STREAM_TO_SEND = "STREAM_TO_SEND";
       public CustomStreamerInterceptor () {
             super( Phase.WRITE_ENDING );
             addAfter( SoapOutEndingInterceptor.class.getName() );
       }
       @Override
       public void handleMessage( Message message ) throws Fault {
             try {
                    InputStream toSend = (InputStream) message.get( STREAM_TO_SEND );
                    if ( toSend != null ) {
                           toSend.reset();
                           LoadingByteArrayOutputStream lBos = new LoadingByteArrayOutputStream();
                           IOUtils.copy( toSend, lBos );
                           CacheAndWriteOutputStream cawos = (CacheAndWriteOutputStream) message.getContent( OutputStream.class );
                           cawos.resetOut( lBos, false );//fail !
                    }
             }
             catch ( Exception e ) {
                    throw new Fault( e );
             }
       }
}

谢谢你的帮助,这将非常有用。

共有1个答案

赫连骏
2023-03-14

我认为最好创建一个“经典”HTTP客户端,因为CXF不是为这种情况设计的,更常见的是使用它来列表从java到XML的对象...对你来说幸运的是,我用拦截器来处理这个问题。您可以编写一个拦截器,将CXF准备发送到服务器的输出流对象中的流复制出来。您需要小心拦截器的阶段和顺序,因为如果您使用Logging拦截器,您可能希望记录传出流。此拦截器可以完成这项工作,请确保它在任何日志拦截器之后运行。CXF 2.7.18的代码:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.lang.CharEncoding;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.StaxOutInterceptor;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PassePlatClientInterceptorOut extends AbstractPhaseInterceptor<Message> {
private static final Logger LOG = LoggerFactory.getLogger( PassePlatClientInterceptorOut.class );

private final Exchange exchangeToReadFrom;

public PassePlatClientInterceptorOut( final Exchange exchange ) {
    super( Phase.PRE_STREAM );
    addBefore( StaxOutInterceptor.class.getName() );
    this.exchangeToReadFrom = exchange;
}

@Override
public void handleMessage( Message message ) {
    InputStream is = (InputStream) exchangeToReadFrom.get( PassePlatServerInterceptorIn.PASSE_PLAT_INTERCEPTOR_STREAM_SERVEUR );
    if ( is != null ) {
        message.put( org.apache.cxf.message.Message.ENCODING, CharEncoding.UTF_8 );
        OutputStream os = message.getContent( OutputStream.class );
        try {
            IOUtils.copy( is, os );
            is.close();
        }
        catch ( IOException e ) {
            LOG.error( "Error ...", e );
            message.setContent( Exception.class, e );
            throw new Fault( new Exception( "Error ...", e ) );
        }
        boolean everythingOK = message.getInterceptorChain().doInterceptStartingAt( message,
                org.apache.cxf.interceptor.MessageSenderInterceptor.MessageSenderEndingInterceptor.class.getName() );
        if ( !everythingOK ) {
            LOG.error( "Error ?" );
            throw new Fault( new Exception( "Error ..." ) );
        }
    }
}

}

要创建拦截器:

cxfClient.getInInterceptors().add( new PassePlatClientInterceptorIn( exchange ) );
 类似资料:
  • 我是camel的新手,我正在尝试使用camel cxf组件创建一个soap WebService。我从骆驼的样本开始。我已经配置了一个使用cxf组件的路由,并添加了一个处理器来处理请求。我在用于处理服务的bean中收到了请求,但我无法将响应发送回客户机。提前致谢 Sysout语句被打印在控制台上,但我得到的是一个空正文的soap响应。 以下是我从浏览器访问http://localhost:9080

  • 问题内容: 我想修改一个传出的SOAP请求。我想从信封的主体中删除2个xml节点。我设法设置了一个拦截器,并将生成的消息的String值设置为端点。 但是,以下代码似乎不起作用,因为未按预期方式编辑外发消息。是否有人对如何执行此操作有一些代码或想法? 问题答案: 我今天也有这个问题。经过大量的哭泣和咬牙切齿,我能够在CXF源附带的configuration_interceptor演示中更改Stre

  • 我有一个Web服务,我试图使用以下客户端代码调用它: 在服务器端(Tomcat),webservice实现如下: CxfAdd。java: CxfAddImpl。java: 但是,当我运行客户端代码时,在服务器端我得到以下错误: 似乎我没有发送ws-addressing属性,有人能帮我找出代码中的错误或缺失吗?非常感谢。

  • 问题:CXF能否基于WS-SecurityPolicy文件自动为客户端配置WS-Security? 如果是的话,是否有任何关于实际这样做的文件?我花了几个小时查看CXF站点并进行搜索,但没有找到答案。 CXF留档显示“CXF 2.2引入了对使用WS-SecurityPolicy配置WSS4J的支持,而不是WS-Security页面上记录的自定义配置”,并且还显示“在CXF 2.2中,如果cxf-r

  • 我正在使用CamelCXFendpoint连接到我的soap服务器。我想为客户端的请求添加超时。我正在为此使用continuationTimeout选项。但它不起作用。请求超时,而不等待我配置的时间。 下面是我的endpoint配置。

  • 问题内容: 我正在尝试使用CXF创建Web服务客户端以使用WCF Web服务。当我使用wsdl2java时,它将生成具有JAXBElement类型而不是String的对象。 我读到有关使用jaxb bindings.xml文件设置generateElementProperty =“ false”来尝试解决此问题的信息,但是我使用的Web服务包含7个导入的架构。 如何在所有七个模式上指定,还是可以将