Включение запросов перекрестных запросов для WebSockets в Spring

У меня есть OpenShift Wildfly сервер. Я создаю веб-сайт с помощью рамки Spring MVC. На одном из моих веб-страниц также используется соединение WebSocket. На стороне сервера я использовал библиотеку @ServerEndpoint и javax.websocket.* для создания моего websocket:

package com.myapp.spring.web.controller;
import java.io.IOException;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.springframework.web.socket.server.standard.SpringConfigurator;


@ServerEndpoint(value="/serverendpoint", configurator = SpringConfigurator.class)

public class serverendpoint {

    @OnOpen
    public void handleOpen () {
        System.out.println("JAVA: Client is now connected...");
    }

    @OnMessage
    public String handleMessage (Session session, String message) throws IOException {

        if (message.equals("ping")) {
//            return "pong"
                session.getBasicRemote().sendText("pong");
        }
        else if (message.equals("close")) {
            handleClose();
            return null;
        }
        System.out.println("JAVA: Received from client: "+ message);
        MyClass mc = new MyClass(message);
        String res = mc.action();
        session.getBasicRemote().sendText(res);
        return res;
    }

    @OnClose
    public void handleClose() {
        System.out.println("JAVA: Client is now disconnected...");
    }

    @OnError
    public void handleError (Throwable t) {
        t.printStackTrace();
    }
}

OpenShift предоставляет URL по умолчанию, поэтому все мои веб-страницы (html файлы) имеют общее (каноническое) имя хоста. Для простоты я называю этот URL URL A (projectname-domainname.rhclound.com). Я создал псевдоним CNAME, URL A, который называется URL B (скажем https://www.mywebsite.tech). URL B является безопасным, так как он имеет https.

Я использую клиент JavaScript для подключения к WebSocket по пути /serverendpoint. URI, который я использую в файле html webpage, test.html, является следующим:

var wsUri = "wss://" + "projectname-domainname.rhclound.com" + ":8443" + "/serverendpoint";

Когда я открываю URL A (projectname-domainname.rhclound.com/test), WebSocket подключается, и все работает нормально. Однако, когда я пытаюсь подключиться к websocket с помощью URL B ( https://mywebsite.tech/test), клиент JavaScript немедленно подключается и отключается.

Вот сообщение с консоли, которое я получаю:

введите описание изображения здесь

Вот мой код JavaScript, который подключается к WebSocket:

/****** BEGIN WEBSOCKET ******/
            var connectedToWebSocket = false;
            var responseMessage = '';
            var webSocket = null;
            function initWS() {
                connectedToWebSocket = false;
                var wsUri = "wss://" + "projectname-domainname.rhcloud.com" + ":8443" + "/serverendpoint";
                webSocket = new WebSocket(wsUri); // Create a new instance of WebSocket using usUri
                webSocket.onopen = function(message) {
                    processOpen(message);
                };
                webSocket.onmessage = function(message) {
                    responseMessage = message.data;
                    if (responseMessage !== "pong") { // Ping-pong messages to keep a persistent connection between server and client
                        processResponse(responseMessage);
                    }
                    return false;
                };
                webSocket.onclose = function(message) {
                    processClose(message);
                };
                webSocket.onerror = function(message) {
                    processError(message);
                };
                console.log("Exiting initWS()");
            }

            initWS(); //Connect to websocket

            function processOpen(message) {
                connectedToWebSocket = true;
                console.log("JS: Server Connected..."+message);
            }

            function sendMessage(toServer) { // Send message to server
                if (toServer != "close") {
                    webSocket.send(toServer);
                } else {
                    webSocket.close();
                }
            }

            function processClose(message) {
                connectedToWebSocket = false;
                console.log("JS: Client disconnected..."+message);
            }

            function processError(message) { 
                userInfo("An error occurred. Please contact for assistance", true, true);
            }
            setInterval(function() {
                if (connectedToWebSocket) {
                    webSocket.send("ping");
                }
            }, 4000); // Send ping-pong message to server
/****** END WEBSOCKET ******/

После многого отладки и тестирования различных вещей я пришел к выводу, что это проблема, возникающая из-за Spring Framework. Это связано с тем, что до того, как я представил Spring Framework в моем проекте, URL B мог подключиться к WebSocket, но после введения Spring он не может.
Я прочитал на spring веб-сайт о политике WebSocket. Я столкнулся с их той же политикой происхождения, которая гласит, что псевдоним URL B не может подключаться к WebSocket, потому что он не совпадает с тем, t24 > есть. Чтобы решить эту проблему, я отключил одну и ту же политику происхождения с помощью WebSockets, как сказано в документации, поэтому я добавил следующий код. Я думал, что это исправит мою ошибку. Вот что я добавил:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }

}

Однако это не устранило проблему, поэтому я добавил следующий метод к ApplicationConfig, который extends WebMvcConfigurerAdapter:

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**").allowedOrigins("https://www.mywebsite.com");
}

Это тоже не сработало. Затем я попробовал это:

package com.myapp.spring.security.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class MyCorsFilter {

//  @Bean
//  public FilterRegistrationBean corsFilter() {
//      System.out.println("Filchain");
//      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//      CorsConfiguration config = new CorsConfiguration();
//      config.setAllowCredentials(true);
//      config.addAllowedOrigin("https://www.mymt.tech");
//      config.addAllowedHeader("*");
//      config.addAllowedMethod("*");
//      source.registerCorsConfiguration("/**", config);
//      FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
//      bean.setOrder(0);
//      System.out.println("Filchain");
//      return bean;
//  }

     @Bean
     public CorsFilter corsFilter() {
         System.out.println("Filchain");
         UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
         CorsConfiguration config = new CorsConfiguration();
         config.setAllowCredentials(true); // you USUALLY want this
         config.addAllowedOrigin("*");
         config.addAllowedHeader("*");
         config.addAllowedMethod("*");
         config.addAllowedMethod("*");
         source.registerCorsConfiguration("/**", config);
         System.out.println("Filchain");
         return new CorsFilter(source);
     }

}

Это тоже не сработало.

Я даже изменил var wsURI в JS-коде на следующее: var wsUri = "wss://" + "www.mywebsite.com" + ":8443" + "/serverendpoint"; Тогда var wsUri = "wss://" + "mywebsite.com" + ":8443" + "/serverendpoint";

Когда я это сделал, Google Chrome дал мне ошибку, заявив, что рукопожатие потерпело неудачу. Однако, когда у меня есть этот URL-адрес, var wsUri = "wss://" + "projectname-domianname.rhcloud.com" + ":8443" + "/serverendpoint";, я не получил сообщение об ошибке, которое не произошло, но я получил сообщение о том, что соединение открыто и закрыто немедленно (как видно выше).

Итак, как я могу это исправить?

Ответ 1

Вы пытались реализовать WebMvcConfigurer и переопределить метод addCorsMappings()? Если нет, попробуйте это и посмотрите.

@EnableWebMvc
@Configuration
@ComponentScan
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {

        registry.addMapping("/**")
        .allowedOrigins("*")
        .allowedMethods("GET", "POST")
        .allowedHeaders("Origin", "Accept", "Content-Type", "Authorization")
        .allowCredentials(true)
        .maxAge(3600);

    }

}

Ответ 2

Последнее решение не работает для WebSocket.