Соединение WebSocket не удается при развертывании веб-приложения Spring на сервере в моем домене

Я столкнулся с проблемой подключения к WebSocket в моем веб-приложении Spring. Локально, когда я запускаю приложение, соединения WebSocket устанавливаются успешно. Однако после развертывания приложения на сервере в моем домене соединения WebSocket не могут быть установлены. В консоли браузера отображается следующая ошибка:

WebSocket connection to 'wss://merkeido.com/ws/776/1lq4jnfq/websocket' failed:

Дополнительная информация:

  • Приложение работает нормально локально, но при развертывании на сервере возникают проблемы.
  • Сервер возвращает код состояния 403 (Запрещено).
  • Конечная точка WebSocket — wss://merkeido.com/ws/776/1lq4jnfq/websocket.

Что я пробовал:

  1. Обеспечение поддержки WebSocket включено в конфигурации Spring.
  2. Проверка URL-адресов и конфигураций конечных точек WebSocket.
  3. Проверка журналов сервера на наличие соответствующих сообщений об ошибках.

Вопрос: Что может привести к сбою соединения WebSocket при развертывании, в частности, к ошибке 403 (запрещено)? Будем очень признательны за любые идеи или предложения по устранению неполадок. Спасибо!

Конфигурация веб-сокета: Вот мой класс конфигурации WebSocket:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

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

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

HTML/JavaScript: А вот мой код HTML/JavaScript для установления соединений WebSocket:

<script src = "https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.4/sockjs.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

<script th:inline = "javascript"> 
    'use strict'; 
    
    let stompClient = null;
    let selectedUserId = null;
    let userId = user_id;
    
    connect();
    function connect() {
        const socket = new SockJS('/ws');
        stompClient = Stomp.over(socket);
    
        stompClient.connect({}, onConnected, onError);
    }
    
    function onConnected() {
        stompClient.subscribe(`/user/${userId+""}/queue/messages`, onMessageReceived);
        stompClient.subscribe(`/user/public`, onMessageReceived);
    
        // Register the connected user
        stompClient.send("/app/user.addUser",
            {},
            JSON.stringify({id: userId+"", c_status: 'ONLINE'})
        );
        
        findAndDisplayConnectedUsers().then();
    }
</script>

Фактическая ошибка на моей консоли:

Opening Web Socket...
websocket.js:6 WebSocket connection to 'wss://merkeido.com/ws/776/1lq4jnfq/websocket' failed: 
e.exports @ websocket.js:6
/ws/776/in3mqa1z/xhr_streaming?t=1714645083452:1 
        
        
       Failed to load resource: the server responded with a status of 403 ()
stomp.min.js:8 Web Socket Opened...
stomp.min.js:8 >>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
102
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел решение проблемы, внеся несколько изменений в конфигурации WebSocket и WebSecurity.

Конфигурация веб-сокета

Сначала я отредактировал свою конечную точку в классе WebSocketConfig, чтобы обеспечить разрешенные источники:

@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) {
        // Ensure allowed origins
        registry.addEndpoint("/ws")
                .setAllowedOrigins("https://domain-name.com")  // Replace with your client domain
                .withSockJS();
    }
}

Конфигурация веб-безопасности

Затем я настроил конфигурацию WebSecurity для обработки CORS и CSRF:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
            .authorizeRequests()
            .antMatchers("/**").permitAll();  // Allow all requests temporarily
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("https://domain-name.com");  // Replace with your client domain
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

Объяснение Конфигурация веб-сокета:

Метод RegisterStompEndpoints регистрирует конечную точку /ws для STOMP через WebSocket и разрешает соединения с https://domain-name.com с использованием SockJS в качестве запасного варианта. Конфигурация веб-безопасности:

Метод configure отключает CSRF и включает CORS, временно разрешая все запросы. Компонент corsFilter настраивает CORS для разрешения учетных данных и запросов от https://domain-name.com, а также всех заголовков и методов. И вот так это работает. Эта настройка гарантирует, что ваше соединение WebSocket и настройки безопасности правильно согласованы, что позволяет вашему клиенту подключаться без проблем.

Другие вопросы по теме