stacktrace
stacktrace

Reputation: 557

WebSocketStompClient won't connect to SockJS endpoint

I'm playing around with the new (as of version 4.2) java STOMP client support. My starting point is the getting started guide (Using WebSocket to build an interactive web application).

The following endpoint is provided in the example:

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/hello").withSockJS();
}

I can successfully connect using the browser client. When attempting to connect to this endpoint using the java stomp client using the following:

WebSocketClient transport = new StandardWebSocketClient();
WebSocketStompClient stompClient = new WebSocketStompClient(transport);
stompClient.setMessageConverter(new StringMessageConverter());
String url = "ws://127.0.0.1:8080/hello";       
ListenableFuture<StompSession> future = stompClient.connect(url,myHandler);

I encounter the following exception:

08:56:30.629 [SimpleAsyncTaskExecutor-1] DEBUG o.s.m.simp.stomp.DefaultStompSession - Failed to connect session id=4e6737da-8f68-691d-375f-9e46f48bc149
javax.websocket.DeploymentException: The HTTP response from the server [HTTP/1.1 200 OK
] did not permit the HTTP upgrade to WebSocket
    at org.apache.tomcat.websocket.WsWebSocketContainer.parseStatus(WsWebSocketContainer.java:637) ~[tomcat-embed-websocket-8.0.20.jar:8.0.20]
    at org.apache.tomcat.websocket.WsWebSocketContainer.processResponse(WsWebSocketContainer.java:621) ~[tomcat-embed-websocket-8.0.20.jar:8.0.20]
    at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServer(WsWebSocketContainer.java:309) ~[tomcat-embed-websocket-8.0.20.jar:8.0.20]
    at org.springframework.web.socket.client.standard.StandardWebSocketClient$1.call(StandardWebSocketClient.java:152) ~[spring-websocket-4.2.0.BUILD-SNAPSHOT.jar:4.2.0.BUILD-SNAPSHOT]
    at org.springframework.web.socket.client.standard.StandardWebSocketClient$1.call(StandardWebSocketClient.java:149) ~[spring-websocket-4.2.0.BUILD-SNAPSHOT.jar:4.2.0.BUILD-SNAPSHOT]
    at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.8.0]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0] 

Upon further investigation I changed the server endpoint configuration based on TomcatWebSocketTestServer.java used in StompWebSocketIntegrationTests.java as follows:

RequestUpgradeStrategy upgradeStrategy = new TomcatRequestUpgradeStrategy();
registry.addEndpoint("/hello")
    .setHandshakeHandler(new DefaultHandshakeHandler(upgradeStrategy))
    .setAllowedOrigins("*");

I can now connect, but the browser clients cannot.

GET http://localhost:8080/hello/info 404 (Not Found) 

If I add .withSockJs() to the endpoint configuration:

RequestUpgradeStrategy upgradeStrategy = new TomcatRequestUpgradeStrategy();
registry.addEndpoint("/hello")
    .setHandshakeHandler(new DefaultHandshakeHandler(upgradeStrategy))
    .setAllowedOrigins("*")
    .withSockJs();

the browser clients can connect again, but the java client is back to the original error.

Should I be able to share the same endpoint between both clients or do I need to configure two separate endpoints in this case?

Upvotes: 14

Views: 17514

Answers (3)

qyvlik
qyvlik

Reputation: 39

You can check the http filter(such as shiro filter) or HandlerInterceptor.

WebSocket connnect base on http connect, there is a ws url like this: ws://localhost:8080/ws-endpoint, If you have a http filter or http interceptor on the uri ws-endpoint, the http filter or http interceptor will be effect before websocket upgrade. So remove the uri's http filter or http interceptor.

Upvotes: 0

stacktrace
stacktrace

Reputation: 557

The following configuration works:

RequestUpgradeStrategy upgradeStrategy = new TomcatRequestUpgradeStrategy();
registry.addEndpoint("/hello")
        .withSockJS();

registry.addEndpoint("/hello")
        .setHandshakeHandler(new DefaultHandshakeHandler(upgradeStrategy))
        .setAllowedOrigins("*");

Not sure if this is by design (i.e. two endpoints with the same path)?

A better solution based on Brian-Clozel's feedback is to use the java SockJsClient as a transport when configuring the WebSocketStompClient:

List<Transport> transports = new ArrayList<>(1);
transports.add(new WebSocketTransport( new StandardWebSocketClient()) );
WebSocketClient transport = new SockJsClient(transports);
WebSocketStompClient stompClient = new WebSocketStompClient(transport);

which allows the use of only one endpoint to which the java and javascript clients can both connect:

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/hello").withSockJS();
}

Upvotes: 26

Brian Clozel
Brian Clozel

Reputation: 59211

As stated in the reference documentation: when enabling SockJS, multiple transports are configured for you. First, the client sends a "GET /info" request to know about supported transports and then sends a request depending on its capabilities:

"http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport}"

Now you don't need to duplicate your configuration for you "/hello" endpoint. You'd rather directly use the websocket endpoint, or better, use the Java SockJS client with a websocket transport. See the complete example in the reference documentation.

Upvotes: 6

Related Questions