【发布时间】: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