我一直在尝试通过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日下午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 Web服务的前端。这个想法是客户端将通过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而不是Webservice端点。我的期望是,我将在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的日志记录。这说明网易引发了java.lang.NoSuchMethodError:io.netty.channel.DefaultChannelId.newInstance()Lio / netty / channel / DefaultChannelId;
也许我有netty的版本兼容性问题。我看到的导入到项目中的版本是4.1.33。我没有声明它是一个传递依赖。
答案 0 :(得分:0)
好吧,我实际上设法独自破解了它。我将发布完成答案。显然,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超时,但是我认为它应该可以工作,但我缺少一些小东西。无论如何,我没有更多的时间可花,我对Aproach 1感到满意。