【问题标题】:SOAP over Websocket with Appache CXF and Embedded JettySOAP over Websocket 与 Appache CXF 和 Embedded Jetty
【发布时间】:2019-06-12 12:52:25
【问题描述】:

我一直在尝试通过 CXF 设置一个使用 Websocket 作为传输协议的 SOAP 端点,并通过 CXF 实现调用它。带有嵌入式码头。我已经尝试了几种方法,但不幸的是,这些方法都没有奏效。这是我所做的:

方法 1. 根据 CXF 文档,支持 websocket 作为传输协议,并通过

提供支持
<dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-websocket</artifactId>
            <version>3.3.2</version>
</dependency>

我已经设置了以下依赖项:

 <dependency>
        <groupId>org.asynchttpclient</groupId>
        <artifactId>async-http-client</artifactId>
        <version>2.0.39</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>3.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>3.3.2</version>
    </dependency>
    <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.3.2</version>
    </dependency>

我执行的代码如下:

Endpoint endpoint = Endpoint.create(new MyHelloWorldServicePortType() {

            @Override
            public String sayHello(HelloMessage message) throws FaultMessage {

                return message.sayHello();
            }
};
((org.apache.cxf.jaxws.EndpointImpl)endpoint).getFeatures().add(new 
WSAddressingFeature());
endpoint.publish("ws://localhost:8088/MyHelloWorldService"  );
URL wsdlDocumentLocation =  new URL("file:/path to wsdl file");
 String servicePart = "MyHelloWorldService";
 String namespaceURI = "mynamespaceuri";
 QName serviceQN = new QName(namespaceURI, servicePart);
Service service = Service.create(wsdlDocumentLocation, serviceQN);
 MyHelloWorldServicePortType port = service.getPort( MyHelloWorldServicePortType.class);

portType.sayHello(new HelloMessage("Say Hello"));

这段代码的结果是:

严重:[ws] onError java.util.concurrent.TimeoutException:请求 在 60000 毫秒后超时未连接 org.asynchttpclient.netty.timeout.TimeoutTimerTask.expire(TimeoutTimerTask.java:43) 在 org.asynchttpclient.netty.timeout.RequestTimeoutTimerTask.run(RequestTimeoutTimerTask.java:48) 在 io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:682) 在 io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:757) 在 io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:485) 在 java.base/java.lang.Thread.run(Thread.java:834)

君。 2019 年 12 月 12 日下午 1:13:33 org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit$AhcWebSocketWrappedOutputStream 连接严重:无法连接 java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException:请求超时 在 60000 毫秒后未连接 java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395) 在 java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999) 在 org.asynchttpclient.netty.NettyResponseFuture.get(NettyResponseFuture.java:172) 在 org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit$AhcWebSocketWrappedOutputStream.connect(AhcWebSocketConduit.java:309) 在 org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit$AhcWebSocketWrappedOutputStream.setupWrappedStream(AhcWebSocketConduit.java:167) 在 org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleHeadersTrustCaching(HTTPConduit.java:1343) 在 org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.onFirstWrite(HTTPConduit.java:1304) 在 org.apache.cxf.io.AbstractWrappedOutputStream.write(AbstractWrappedOutputStream.java:47) 在 org.apache.cxf.io.AbstractThresholdOutputStream.write(AbstractThresholdOutputStream.java:69) 在 org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1356) 在 org.apache.cxf.transport.websocket.ahc.AhcWebSocketConduit$AhcWebSocketWrappedOutputStream.close(AhcWebSocketConduit.java:139) 在 org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)

我完全不知道为什么。当我尝试通过 URL 上的 websocket chrome 客户端进行连接时。它说成功。同时通过客户端连接时显示超时。

方法 2。

我决定欺骗 CXF 并提供一个手工制作的 Websocket 端点,该端点将用作 CXF 网络服务的前端。这个想法是客户端将通过 websocket 发送消息,消息将被解包,然后通过 CXF 发送。此方法与此处的方法非常相似,但此处使用 JMS 作为传输方式

https://github.com/pbielicki/soap-websocket-cxf

为了做到这一点,我创建了以下 Websocket 端点:

@ServerEndpoint("/jaxWSFront")
public class JaxWSFrontEnd {


      @OnOpen
      public void onOpen(final Session session) {
           System.out.println("Hellooo");

      }

      @OnMessage
      public void onMessage(String mySoapMessage,final Session session) throws Exception{
    //  The goal here is to get the soap message and redirect it via SOAP web //service. The JaxWSFacade acts as a point that understands websocket and then //gets the soap content and sends it to enpoint that understands SOAP.

       session.getBasicRemote().sendText("Helllo . Now you see me.");

       System.out.println("Hellooo again");
      }

      @OnClose
      public void onClose(Session session, CloseReason closeReason) {
           System.out.println("Hellooo");
      }

      @OnError
      public void onError(Throwable t, Session session) {
           System.out.println("Hellooo");
      }

} 

现在我将我的客户端代理指向 jaxWsFrontEnd 而不是 web 服务端点。我的期望是我将在 onMessage 方法中收到 SOAP 消息,然后我将能够将 SOAP 转发到 CXF Web 服务。

现在我的代码如下所示:

server = new Server(8088);

            ServletContextHandler context = new ServletContextHandler();
            context.setContextPath( "/" );
            server.setHandler(context);

            ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
            container.addEndpoint(JaxWSFrontEnd.class);

            server.setHandler( context );
            server.start();
  Endpoint endpoint = Endpoint.create(new MyHelloWorldServicePortType() {

                @Override
                public String sayHello(HelloMessage message) throws FaultMessage {

                    return message.sayHello();
                }
    };
    ((org.apache.cxf.jaxws.EndpointImpl)endpoint).getFeatures().add(new 
    WSAddressingFeature());

    URL wsdlDocumentLocation =  new URL("file:/path to wsdl file");
     String servicePart = "MyHelloWorldService";
     String namespaceURI = "mynamespaceuri";
     QName serviceQN = new QName(namespaceURI, servicePart);
    Service service = Service.create(wsdlDocumentLocation, serviceQN);
     MyHelloWorldServicePortType port = service.getPort( MyHelloWorldServicePortType.class);

    portType.sayHello(new HelloMessage("Say Hello"));

对于第二种方法,除了方法 1 之外,我还有以下依赖项:

<dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>websocket-common</artifactId>
                    </dependency>
       <dependency>
          <groupId>org.eclipse.jetty.websocket</groupId>
          <artifactId>javax-websocket-server-impl</artifactId>

        </dependency>

方法 2 的结果与方法 1 的结果完全一样,我收到的例外情况相同,只有一点点不同。 当我使用 Chrome websocket 客户端并将其直接指向 jaxWsFrontend 时,我能够成功发送消息。 为什么我无法通过 CXF websocket 传输机制连接到 websocket ????我做错了什么?

更新:启用从 NETTY 的日志记录。看来 netty 抛出了 java.lang.NoSuchMethodError: io.netty.channel.DefaultChannelId.newInstance()Lio/netty/channel/DefaultChannelId;

也许我有一个与 netty 的版本兼容性问题。项目中导入我能看到的版本是4.1.33。这是一个传递依赖,我没有声明它。

【问题讨论】:

    标签: java soap websocket jetty cxf


    【解决方案1】:

    好吧,实际上我自己设法破解了它。我将发布答案以完成。显然,CXF 家伙应该更新他们的文档 IMO。在他们的网站上说,为了启用 Websocket 作为传输协议,我们需要 cxf-rt-transports-websocket 依赖。

    他们没有说的是您还需要 async-http-client 不是任何版本,而是 2.0.39 一个相当旧的版本。问题是它自动包含对 netty 4.1 的传递依赖,并且上面指定的错误开始显现。您实际需要的是 nett 4.0.56

    这是使事情对我有用的片段:

    <dependency>
                <groupId>org.asynchttpclient</groupId>
                <artifactId>async-http-client</artifactId>
                <version>2.0.39</version>
                 <exclusions>
                    <exclusion>
                        <groupId>io.netty</groupId>
                        <artifactId>netty-buffer</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.netty</groupId>
                        <artifactId>netty-codec-http</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.netty</groupId>
                        <artifactId>netty-handler</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.netty</groupId>
                        <artifactId>netty-transport-native-epoll</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.netty</groupId>
                        <artifactId>netty-transport</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.netty</groupId>
                        <artifactId>netty-common</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.netty</groupId>
                        <artifactId>netty-codec</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.netty</groupId>
                        <artifactId>netty-all</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.0.56.Final</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-websocket</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-transports-http-jetty</artifactId>
                <version>3.3.2</version>
        </dependency>
    

    方法 1 有效 方法 2 我设法触发了 onConnect 事件,即 onMessage 超时,但我认为它应该可以工作,但我缺少一些小东西。无论如何,我没有更多时间花在上面,我对方法 1 很满意。

    【讨论】:

      猜你喜欢
      • 2017-01-19
      • 1970-01-01
      • 2012-09-08
      • 2012-07-17
      • 1970-01-01
      • 1970-01-01
      • 2021-05-16
      • 2021-08-13
      • 1970-01-01
      相关资源
      最近更新 更多