0

I am highly confused with spring boot websockets. I have followed this tutorial https://www.youtube.com/watch?v=TywlS9iAZCM&t=2367s to create the Websocket backend. I wanted to test it with the Websocket capabilities of Postman and also created a console Application in C# to test and play around with the Websockets, however, i always get 404 back. This is really confusing for me since when i look into the logs of the spring boot application it looks like the Websocket request is always treated as a normal GET request, which also does not make a lot of sense to me. I already looked at this question spring boot websocket api 404 not found and this one Spring websocket getting 404 not found but in all tutorials i have watched so far nobody is using the Websocketconfig which implements WebSocketConfigurer and adding the @Controller annotation to my config did not change anything at all. What am i missing and what am i doing wrong?

The logs:

2023-07-11T11:11:23.890+02:00 TRACE 19376 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'stompWebSocketHandlerMapping'
2023-07-11T11:11:23.890+02:00 TRACE 19376 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'webSocketHandlerMapping'
2023-07-11T11:11:23.890+02:00 TRACE 19376 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'resourceHandlerMapping'
2023-07-11T11:11:23.892+02:00  INFO 19376 --- [           main] c.e.w.WebSocketTriesBackendApplication   : Started WebSocketTriesBackendApplication in 1.72 seconds (process running for 2.274)
2023-07-11T11:11:23.893+02:00 TRACE 19376 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'springApplicationAdminRegistrar'
2023-07-11T11:11:23.893+02:00 TRACE 19376 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'springApplicationAdminRegistrar'
2023-07-11T11:11:23.893+02:00 TRACE 19376 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'applicationAvailability'
2023-07-11T11:11:23.893+02:00 DEBUG 19376 --- [           main] o.s.b.a.ApplicationAvailabilityBean      : Application availability state LivenessState changed to CORRECT
2023-07-11T11:11:23.894+02:00 TRACE 19376 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'springApplicationAdminRegistrar'
2023-07-11T11:11:23.894+02:00 TRACE 19376 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'springApplicationAdminRegistrar'
2023-07-11T11:11:23.894+02:00 TRACE 19376 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'applicationAvailability'
2023-07-11T11:11:23.894+02:00 DEBUG 19376 --- [           main] o.s.b.a.ApplicationAvailabilityBean      : Application availability state ReadinessState changed to ACCEPTING_TRAFFIC
2023-07-11T11:12:23.659+02:00  INFO 19376 --- [MessageBroker-1] o.s.w.s.c.WebSocketMessageBrokerStats    : WebSocketSession[0 current WS(0)-HttpStream(0)-HttpPoll(0), 0 total, 0 closed abnormally (0 connect failure, 0 send limit, 0 transport error)], stompSubProtocol[processed CONNECT(0)-CONNECTED(0)-DISCONNECT(0)], stompBrokerRelay[null], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], outboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], sockJsScheduler[pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
2023-07-11T11:16:01.904+02:00  INFO 19376 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-07-11T11:16:01.904+02:00  INFO 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-07-11T11:16:01.904+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'multipartResolver'
2023-07-11T11:16:01.904+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.multipart.support.StandardServletMultipartResolver@6e4d781
2023-07-11T11:16:01.904+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'localeResolver'
2023-07-11T11:16:01.904+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver@503209a1
2023-07-11T11:16:01.904+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'themeResolver'
2023-07-11T11:16:01.904+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected org.springframework.web.servlet.theme.FixedThemeResolver@614fac67
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'stompWebSocketHandlerMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'webSocketHandlerMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'welcomePageHandlerMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'welcomePageNotAcceptableHandlerMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'requestMappingHandlerMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'viewControllerHandlerMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'beanNameHandlerMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'routerFunctionMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'resourceHandlerMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'defaultServletHandlerMapping'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'requestMappingHandlerAdapter'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'handlerFunctionAdapter'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'httpRequestHandlerAdapter'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'simpleControllerHandlerAdapter'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'errorAttributes'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'handlerExceptionResolver'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'viewNameTranslator'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected DefaultRequestToViewNameTranslator
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'beanNameViewResolver'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'mvcViewResolver'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'defaultViewResolver'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'viewResolver'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'flashMapManager'
2023-07-11T11:16:01.905+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Detected SessionFlashMapManager
2023-07-11T11:16:01.905+02:00 DEBUG 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
2023-07-11T11:16:01.905+02:00  INFO 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2023-07-11T11:16:01.908+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.w.s.f.OrderedRequestContextFilter  : Bound request context to thread: org.apache.catalina.connector.RequestFacade@4379a6f
2023-07-11T11:16:01.910+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/ws/app/topic/public", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2023-07-11T11:16:01.917+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.w.s.s.s.WebSocketHandlerMapping      : Mapped to HandlerExecutionChain with [org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler@78a0ff63] and 1 interceptors
2023-07-11T11:16:01.925+02:00 DEBUG 19376 --- [nio-8080-exec-1] o.s.w.s.s.t.h.DefaultSockJsService       : Processing transport request: GET http://localhost:8080/ws/app/topic/public
2023-07-11T11:16:01.925+02:00  WARN 19376 --- [nio-8080-exec-1] o.s.w.s.s.t.h.DefaultSockJsService       : "Unknown transport type for http://localhost:8080/ws/app/topic/public"
2023-07-11T11:16:01.926+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : No view rendering, null ModelAndView returned.
2023-07-11T11:16:01.926+02:00 DEBUG 19376 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 404 NOT_FOUND, headers={masked}
2023-07-11T11:16:01.927+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'springApplicationAdminRegistrar'
2023-07-11T11:16:01.927+02:00 TRACE 19376 --- [nio-8080-exec-1] o.s.b.w.s.f.OrderedRequestContextFilter  : Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@4379a6f

The WebsocketConfig:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer
{
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry)
    {
        registry.setApplicationDestinationPrefixes("/app");
        registry.enableSimpleBroker("/topic");
    }

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

Eventlistener:

@Component
@RequiredArgsConstructor
@Slf4j
public class WebSocketEventListener
{
    private final SimpMessageSendingOperations messageTemplate;

    @EventListener
    public void HandleWebSocketDisconnectListener(SessionDisconnectEvent event)
    {
        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
        String username = (String) headerAccessor.getSessionAttributes().get("username");

        if(username != null)
        {
            log.info("User disconncted: " + username);
            var message = ChatMessage.builder()
                    .type(MessageType.LEAVE)
                    .sender(username)
                    .build();

            messageTemplate.convertAndSend("/topic/public", message);
        }
    }
}

Controller:

@Controller
public class ChatController
{
    @MessageMapping("/chat.SendMessage")
    @SendTo("/topic/public")
    public ChatMessage SendMessage(@Payload ChatMessage message)
    {
        return message;
    }

    @MessageMapping("/chat.AddUser")
    @SendTo("/topic/public")
    public ChatMessage AddUser(@Payload ChatMessage message, SimpMessageHeaderAccessor headerAccessor)
    {
        headerAccessor.getSessionAttributes().put("username", message.getSender());
        return message;
    }
}

The method with which i am trying to access the WebSocket:

lass Program
{
    static async Task Main()
    {
        var endpointUrl = "ws://localhost:8080/ws/app/topic/public"; // WebSocket endpoint URL

        using (var client = new ClientWebSocket())
        {
            await client.ConnectAsync(new Uri(endpointUrl), CancellationToken.None); // Connect to the WebSocket endpoint

            // Start a separate task to listen for incoming messages
            _ = ReceiveMessages(client);
            ChatMessage message = new ChatMessage()
            {
                Content = "test",
                Sender = "test",
                Type = MessageType.JOIN
            };
            
            string jsonString = JsonSerializer.Serialize(message);
            // Send a message to the server
            await SendMessage(client, jsonString);
            // Keep the console application running until interrupted
            Console.ReadLine();

            await client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Console application closed", CancellationToken.None);
        }
    }

    static async Task ReceiveMessages(ClientWebSocket client)
    {
        var buffer = new byte[1024];

        while (client.State == WebSocketState.Open)
        {
            var result = await client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

            if (result.MessageType == WebSocketMessageType.Text)
            {
                var messageBytes = new ArraySegment<byte>(buffer, 0, result.Count);
                var message = Encoding.UTF8.GetString(messageBytes.ToArray());
                Console.WriteLine("Received message: " + message);
            }
        }
    }

    static async Task SendMessage(ClientWebSocket client, string message)
    {
        var messageBytes = Encoding.UTF8.GetBytes(message);
        var buffer = new ArraySegment<byte>(messageBytes);

        await client.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
    }
}

0 Answers0