【问题标题】:WebSocketStompClient won't connect to SockJS endpointWebSocketStompClient 不会连接到 SockJS 端点
【发布时间】:2015-08-05 11:04:06
【问题描述】:

我正在使用新的(从 4.2 版开始)java STOMP 客户端支持。我的起点是入门指南 (Using WebSocket to build an interactive web application)。

示例中提供了以下端点:

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

我可以使用浏览器客户端成功连接。尝试使用 java stomp 客户端连接到此端点时,使用以下内容:

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);

我遇到以下异常:

08:56:30.629 [SimpleAsyncTaskExecutor-1] 调试 o.s.m.simp.stomp.DefaultStompSession - 无法连接会话 id=4e6737da-8f68-691d-375f-9e46f48bc149
javax.websocket.DeploymentException:来自服务器的 HTTP 响应 [HTTP/1.1 200 OK
] 不允许 HTTP 升级到 WebSocket
    在 org.apache.tomcat.websocket.WsWebSocketContainer.parseStatus(WsWebSocketContainer.java:637) ~[tomcat-embed-websocket-8.0.20.jar:8.0.20]
    在 org.apache.tomcat.websocket.WsWebSocketContainer.processResponse(WsWebSocketContainer.java:621) ~[tomcat-embed-websocket-8.0.20.jar:8.0.20]
    在 org.apache.tomcat.websocket.WsWebSocketContainer.connectToServer(WsWebSocketContainer.java:309) ~[tomcat-embed-websocket-8.0.20.jar:8.0.20]
    在 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]
    在 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]
    在 java.util.concurrent.FutureTask.run(未知来源)[na:1.8.0]
    在 java.lang.Thread.run(Unknown Source) [na:1.8.0] 

经过进一步调查,我根据 StompWebSocketIntegrationTests.java 中使用的 TomcatWebSocketTestServer.java 更改了服务器端点配置,如下所示:

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

我现在可以连接,但浏览器客户端不能。

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

如果我将 .withSockJs() 添加到端点配置:

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

浏览器客户端可以重新连接,但是java客户端又回到了原来的错误。

我应该能够在两个客户端之间共享同一个端点,还是在这种情况下我需要配置两个单独的端点?

【问题讨论】:

    标签: java spring spring-websocket


    【解决方案1】:

    你可以检查http过滤器(如shiro过滤器)或HandlerInterceptor。

    WebSocket connnect 基于http connect,有这样一个ws url:ws://localhost:8080/ws-endpoint,如果你在uri ws-endpoint上有http过滤器或者http拦截器,http过滤器或者http拦截器将在websocket升级之前生效。所以去掉uri的http过滤器或者http拦截器。

    【讨论】:

    • 请多解释一下
    • WebSocket connnect 基于http connect,有这样的ws url:ws://localhost:8080/ws-endpoint,如果你在uri ws-endpoint上有http过滤器或者http拦截器,http过滤器或http拦截器将在websocket升级之前生效。所以去掉uri的http过滤器或者http拦截器。 @jan-Černý
    【解决方案2】:

    以下配置有效:

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

    不确定这是否是设计使然(即具有相同路径的两个端点)?

    根据 Brian-Clozel 的反馈,一个更好的解决方案是在配置 WebSocketStompClient 时使用 java SockJsClient 作为传输:

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

    它只允许使用 java 和 javascript 客户端都可以连接的一个端点:

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

    【讨论】:

      【解决方案3】:

      the reference documentation 中所述:启用 SockJS 时,会为您配置多个传输。首先,客户端发送"GET /info" 请求以了解支持的传输,然后根据其功能发送请求:

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

      现在您无需为"/hello" 端点复制配置。您宁愿直接使用 websocket 端点,或者更好地使用带有 websocket 传输的 Java SockJS 客户端。见the complete example in the reference documentation

      【讨论】:

      • 谢谢,您的回答很有帮助。我已根据您的反馈使用新配置更新了我的答案。抱歉,我还不能投票(声望点不够)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-13
      • 2015-09-17
      • 2015-10-27
      • 2013-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多