Spring Boot Websocket 在 SockJS 客户端测试中抛出“连接被拒绝”

Posted

技术标签:

【中文标题】Spring Boot Websocket 在 SockJS 客户端测试中抛出“连接被拒绝”【英文标题】:Spring Boot Websocket Throws "Connection Refused" in SockJS Client Test 【发布时间】:2017-07-14 13:39:35 【问题描述】:

到目前为止,我正在开发一个提供简单 REST 资源的 Spring Boot Server 项目。为了向客户端推送通知,我想添加一个 websocket 连接。为了测试这种连接,我根据本教程使用 SockJS 客户端编写了一个集成测试:

http://rafaelhz.github.io/testing-websockets/

问题是连接被拒绝并出现以下错误:

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:9090/websocket/info": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)

我的Websocket配置如下:

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer 

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) 
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) 
        registry
                .addEndpoint("/websocket")
                .setAllowedOrigins("*")
                .withSockJS();
    


我可以看到套接字端点映射到日志中:

2017-07-14 15:22:59.561  INFO 13765 --- [           main] o.s.w.s.s.s.WebSocketHandlerMapping      : Mapped URL path [/websocket/**] onto handler of type [class org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler]

在application.yml文件中服务器端口设置为9090:

server:
 port: 9090

以下单元测试无法连接到套接字:

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import org.springframework.messaging.simp.stomp.StompFrameHandler;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;

import java.lang.reflect.Type;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.SECONDS;

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
//@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class WebSocketConnectionTest 

    static final String WEBSOCKET_URI = "ws://localhost:9090/websocket";
    static final String WEBSOCKET_TOPIC = "/topic";

    BlockingQueue<String> blockingQueue;
    WebSocketStompClient stompClient;

    @Before
    public void setup() 
        blockingQueue = new LinkedBlockingDeque<>();
        stompClient = new WebSocketStompClient(new SockJsClient(
                asList(new WebSocketTransport(new StandardWebSocketClient()))));

        System.out.println(WEBSOCKET_URI);
    

    @Test
    public void shouldReceiveAMessageFromTheServer() throws Exception 
        StompSession session = stompClient
                .connect(WEBSOCKET_URI, new StompSessionHandlerAdapter() )
                .get(1, SECONDS);
        session.subscribe(WEBSOCKET_TOPIC, new DefaultStompFrameHandler());

        String message = "MESSAGE TEST";
        session.send(WEBSOCKET_TOPIC, message.getBytes());

        Assert.assertEquals(message, blockingQueue.poll(1, SECONDS));
    

    class DefaultStompFrameHandler implements StompFrameHandler 
        @Override
        public Type getPayloadType(StompHeaders stompHeaders) 
            return byte[].class;
        

        @Override
        public void handleFrame(StompHeaders stompHeaders, Object o) 
            blockingQueue.offer(new String((byte[]) o));
        
    

连接被拒绝。我相当肯定会发生这种情况,因为 URI 端点不存在,但我不知道为什么。有人知道 URI 中是否有错误,或者是否有其他原因导致连接被拒绝?

【问题讨论】:

你是从 Sock js 调用端点的吗? 我在集成测试中使用 SockJS Java 客户端调用了端点,但失败了。这是你要求的吗? 【参考方案1】:

我找到了问题的原因。端口 9090 上不存在端点。这是因为 @SpringBootTest 注解默认将 WebEnvironment 设置为 WebEnvironment.MOCK。在此配置中,没有启动嵌入式 Servlet,因此不存在端口,只能进行基于 MockMvc 的测试。为了启动嵌入式 servlet 环境必须设置为WebEnvironment.RANDOM_PORTWebEnvironment.DEFINED_PORT。我将其设置为DEFINED_PORT,以便使用我的 application.yml 中的端口 9090。通过设置环境,测试可以正确运行。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)//!!!!!
@ActiveProfiles("test")
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class WebSocketConnectionTest 

String WEBSOCKET_URI = "ws://localhost:9090/websocket";
String WEBSOCKET_TOPIC = "/topic";
.
. 
.

【讨论】:

以上是关于Spring Boot Websocket 在 SockJS 客户端测试中抛出“连接被拒绝”的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring-boot 中路由 websocket 目标

Spring Boot - WebSocket 握手期间出错

Spring-boot 应用程序通过 WebSocket 在 WebPage 上显示 JMS 消息

玩转spring boot——websocket

Spring Boot 集成 websocket(广播式)

spring boot下WebSocket消息推送