javaspringspring-bootwebsocketjhipster

Spring Websocket configuration


I am trying to set up a WebSocket server using Spring Boot and i tried to connect to it using Postman (New Request โ†’ WebSocket). However, I keep getting the following error response:

Error: Unexpected server response: 200

This is my WebSocketConfig.java

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

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

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

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

This is my security config


    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // @formatter:off
        http
            .csrf().disable() // ๐Ÿš€ Fully disables CSRF protection
            .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
            .exceptionHandling()
                .authenticationEntryPoint(problemSupport)
                .accessDeniedHandler(problemSupport)
        .and()
            .headers()
                .contentSecurityPolicy(jHipsterProperties.getSecurity().getContentSecurityPolicy())
            .and()
                .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
            .and()
                .permissionsPolicy().policy("camera=(), fullscreen=(self), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), sync-xhr=()")
            .and()
                .frameOptions().sameOrigin()
        .and()
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/app/**/*.{js,html}").permitAll()
            .antMatchers("/ws/**").permitAll()
            .antMatchers("/i18n/**").permitAll()
            .antMatchers("/content/**").permitAll()
            .antMatchers("/swagger-ui/**").permitAll()
            .antMatchers("/test/**").permitAll()
            .antMatchers("/h2-console/**").permitAll()
            .antMatchers("/api/authenticate").permitAll()
            .antMatchers("/api/register").permitAll()
            .antMatchers("/api/activate").permitAll()
            .antMatchers(HttpMethod.GET, "/api/products/{id}").permitAll()
            .antMatchers("/api/account/reset-password/init").permitAll()
            .antMatchers("/api/account/reset-password/finish").permitAll()
            .antMatchers("/api/_search/products/public").permitAll()
            .antMatchers("/api/products/public").permitAll()
            .antMatchers("/api/products/public/trending").permitAll()
            .antMatchers("/api/product-categories/public").permitAll()
            .antMatchers("/api/admin/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .antMatchers("/api/**").authenticated()
            .antMatchers("/management/health").permitAll()
            .antMatchers("/management/health/**").permitAll()
            .antMatchers("/management/info").permitAll()
            .antMatchers("/management/prometheus").permitAll()
            .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
            .and()
            .httpBasic()
            .and()
            .apply(securityConfigurerAdapter());
        return http.build();
        // @formatter:on
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    private JWTConfigurer securityConfigurerAdapter() {
        return new JWTConfigurer(tokenProvider);
    }
}

and this is the logs i got when starting the app

2025-03-16 02:17:31 2025-03-16T02:17:31.170Z DEBUG 1 --- [           main] o.s.m.s.ExecutorSubscribableChannel      : clientOutboundChannel added SubProtocolWebSocketHandler[StompSubProtocolHandler[v10.stomp, v11.stomp, v12.stomp]] 
2025-03-16 02:17:31 2025-03-16T02:17:31.170Z DEBUG 1 --- [           main] o.s.m.s.ExecutorSubscribableChannel      : clientInboundChannel added WebSocketAnnotationMethodMessageHandler[prefixes=[/app/]] 
2025-03-16 02:17:31 2025-03-16T02:17:31.171Z  INFO 1 --- [           main] o.s.m.s.b.SimpleBrokerMessageHandler     : Starting... 
2025-03-16 02:17:31 2025-03-16T02:17:31.171Z DEBUG 1 --- [           main] o.s.m.s.ExecutorSubscribableChannel      : clientInboundChannel added SimpleBrokerMessageHandler [org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry@1c1ab84e] 
2025-03-16 02:17:31 2025-03-16T02:17:31.171Z DEBUG 1 --- [           main] o.s.m.s.ExecutorSubscribableChannel      : brokerChannel added SimpleBrokerMessageHandler [org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry@1c1ab84e] 
2025-03-16 02:17:31 2025-03-16T02:17:31.171Z  INFO 1 --- [           main] o.s.m.s.b.SimpleBrokerMessageHandler     : BrokerAvailabilityEvent[available=true, SimpleBrokerMessageHandler [org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry@1c1ab84e]] 
2025-03-16 02:17:31 2025-03-16T02:17:31.171Z  INFO 1 --- [           main] o.s.m.s.b.SimpleBrokerMessageHandler     : Started. 
2025-03-16 02:17:31 2025-03-16T02:17:31.171Z DEBUG 1 --- [           main] o.s.m.s.ExecutorSubscribableChannel      : clientInboundChannel added UserDestinationMessageHandler[DefaultUserDestinationResolver[prefix=/user/]] 
2025-03-16 02:17:31 2025-03-16T02:17:31.171Z DEBUG 1 --- [           main] o.s.m.s.ExecutorSubscribableChannel      : brokerChannel added UserDestinationMessageHandler[DefaultUserDestinationResolver[prefix=/user/]]
2025-03-16 02:18:30 2025-03-16T02:18:30.492Z  INFO 1 --- [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 = 3, active threads = 1, queued tasks = 2, completed tasks = 0]

What I Have Tried Connecting using Postman with:


Solution

  • I had to make a change in ClientForwardController file in the Jhipser project. So that this controller does not redirect the websocket request to the clientโ€™s index.html,

    @Controller
    public class ClientForwardController {
    
        /**
         * Forwards any unmapped paths (except those containing a period) to the client {@code index.html}.
         * @return forward to client {@code index.html}.
         */
        @GetMapping(value = "/**/{path:^(?!ws)[^\\.]*}")
        public String forward() {
            return "forward:/";
        }
    }