为啥客户端无法连接到 Java Websocket 服务器?

Posted

技术标签:

【中文标题】为啥客户端无法连接到 Java Websocket 服务器?【英文标题】:Why client cannot connect to the Java Websocket server?为什么客户端无法连接到 Java Websocket 服务器? 【发布时间】:2018-04-09 13:44:54 【问题描述】:

我正在使用 Spring 5 学习 websockets。我使用 this tutorial。但是当我尝试通过 javascript 连接到 websocket 时,出现以下错误:

WebSocket connection to 'ws://localhost:8080/event-emitter' failed: Error during WebSocket handshake: Unexpected response code: 404

当我尝试通过 Java 连接到 websocket 时,出现以下错误:

Exception in thread "main" reactor.ipc.netty.http.client.HttpClientException: HTTP request failed with code: 404.
Failing URI: /event-emitter
Suppressed: java.lang.Exception: #block terminated with an error
    at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:126)
    at reactor.core.publisher.Mono.block(Mono.java:1185)

我的ReactAndSpringDataRestApplication.java

@SpringBootApplication
public class ReactAndSpringDataRestApplication 

@Autowired
private ReactiveWebSocketHandler webSocketHandler;

public static void main(String[] args) 
    SpringApplication.run(ReactAndSpringDataRestApplication.class, args);


@Bean
public HandlerMapping webSocketHandlerMapping() 
    Map<String, WebSocketHandler> map = new HashMap<>();
    map.put("/event-emitter", webSocketHandler);

    SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
    handlerMapping.setOrder(1);
    handlerMapping.setUrlMap(map);
    return handlerMapping;

@Bean
public WebSocketHandlerAdapter handlerAdapter() 
    return new WebSocketHandlerAdapter();


ReactiveWebSocketHandler.java

@Component
public class ReactiveWebSocketHandler implements WebSocketHandler 

private static final ObjectMapper json = new ObjectMapper();

private Flux<String> eventFlux = Flux.generate(sink -> 
    EventTwo event = new EventTwo(Double.toString(Math.random()), new Date().toString());
    try 
        sink.next(json.writeValueAsString(event));
     catch (JsonProcessingException e) 
        sink.error(e);
    
);
private Flux<String> intervalFlux = Flux.interval(Duration.ofMillis(1000L))
        .zipWith(eventFlux, (time, event) -> event);

@Override
public Mono<Void> handle(WebSocketSession webSocketSession) 
    return webSocketSession.send(intervalFlux
            .map(webSocketSession::textMessage))
            .and(webSocketSession.receive()
                    .map(WebSocketMessage::getPayloadAsText)
                    .log());


尝试连接到 websocket 的 JavaScript:

import React, Component from 'react';
import  connect  from 'react-redux';
import '../res/messages.css';
class Messages extends Component 

constructor(props) 
    super(props);
    this.state = messages: [];


getInitialState()
    return  messages : [] 


componentDidMount() 
    var clientWebSocket = new WebSocket("ws://localhost:8080/event-emitter");
    clientWebSocket.onopen = function() 
        console.log("clientWebSocket.onopen", clientWebSocket);
        console.log("clientWebSocket.readyState", "websocketstatus");
        clientWebSocket.send("event-me-from-browser");
    
    clientWebSocket.onclose = function(error) 
        console.log("clientWebSocket.onclose", clientWebSocket, error);
    
    clientWebSocket.onerror = function(error) 
        console.log("clientWebSocket.onerror", clientWebSocket, error);
    
    clientWebSocket.onmessage = function(error) 
        console.log("clientWebSocket.onmessage", clientWebSocket, error);
        this.setState(
                        messages : this.state.messages.concat([ new Date() ])
                    )
    


render() 
    return (
        <div><ul> this.state.messages.map( (msg, idx) => <li key='msg-' + idx > msg </li> )</ul></div>
    )


Java端\Spring中是否应该有额外的websockets配置?为什么客户端连接不上服务器?

【问题讨论】:

【参考方案1】:

我使用了另一个guide的配置。

我在没有 userStats() 的情况下创建了 ChatSocketHandler.java、ReactiveChatApplication.java。

我的Event.java

@Data
public class Event 
private String eventId;
private String eventDt;

public Event() 


public Event(String eventId, String eventDt) 
    this.eventId = eventId;
    this.eventDt = eventDt;


public String getEventId() 
    return eventId;


public void setEventId(String eventId) 
    this.eventId = eventId;


public String getEventDt() 
    return eventDt;


public void setEventDt(String eventDt) 
    this.eventDt = eventDt;


还有我的 JavaScript 文件:

import React, Component from 'react';
import  connect  from 'react-redux';
import '../res/messages.css';
const client = require('../client');

class Messages extends Component 

constructor(props) 
    super(props);
    this.state = messages: [];messages: [];


getInitialState()
    return  messages : [] 


updateMessages(msg)
    this.setState(
        messages : this.state.messages.concat([ msg ])
    )


componentDidMount() 
    var clientWebSocket = new WebSocket("ws://127.0.0.1:8080/websocket/chat");
    clientWebSocket.onopen = function() 
        console.log("clientWebSocket.onopen", clientWebSocket);
        console.log("clientWebSocket.readyState", "websocketstatus");
        clientWebSocket.send("event-me-from-browser");
    
    clientWebSocket.onclose = function(error) 
        console.log("clientWebSocket.onclose", clientWebSocket, error);
    
    clientWebSocket.onerror = function(error) 
        console.log("clientWebSocket.onerror", clientWebSocket, error);
    
    var tmpMsg;
    var _this = this;
    clientWebSocket.onmessage = function(dataFromServer) 
        console.log("clientWebSocket.onmessage", clientWebSocket, dataFromServer);
        var date =  new Date() ;
        tmpMsg =  dataFromServer;
        _this.updateMessages(tmpMsg);
    



render() 
    return (
        <div>
            <ul> this.state.messages.map( (msg) =>
                <li> JSON.parse(msg.data).eventDt </li> )
            </ul>
        </div>

    )

【讨论】:

【参考方案2】:

您是否在上下文(@Bean)上添加了 WebSocketHandlerAdapter 类?如果没有,请尝试在上下文中添加 WebSocketHandlerAdapter 类。

private final WebSocketHandler webSocketHandler;

@Bean
public HandlerMapping webSocketHandlerMapping() 
    Map<String, WebSocketHandler> map = new HashMap<>();
    map.put("/event-emitter", webSocketHandler);

    SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
    handlerMapping.setOrder(1);
    handlerMapping.setUrlMap(map);
    return handlerMapping;


@Bean
public WebSocketHandlerAdapter handlerAdapter() 
    return new WebSocketHandlerAdapter();

【讨论】:

以上是关于为啥客户端无法连接到 Java Websocket 服务器?的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 客户端无法连接到 Spring 4 WebSocket

无法使用 ssl 和 apache 连接到 websocket

高级 Restclient 套接字实现无法连接到 Spring Websocket

Chrome 无法连接到 websocket 服务器(操作码 -1)“握手被取消”

无法使用 django-channels 连接到 websocket,docker 上的 nginx 作为服务

使用 PHP 客户端连接到 websocket